Приветствую всех новых гостей моего сайта а особенно постоянных читателей серии статей по созданию движка на CI3! Сегодня мы будем писать еще один важный модуль, без которого не обойдется ни один движок. Да, это модуль категории - он очень похож на модуль page, который мы программировали в предыдущий раз.
Наши действия и результат получим следующий:
- Сформированную и продуманную таблицу в бд для категорий сайта
- Рендинг категорий в отдельном шаблоне
- Вывод вложенных категорий
- Вывод вложенных страниц категории
- Создание пагинации на bootstrap, для объемных разделов
- Проверку на существование страницы
- Формирование мета данных, для сео продвижения и передачу данных общему шаблону
- Вывод раздела по адресу http://website.name/category/meta_url_category
- Настройка роутинга codeigniter для обработки модуля
Модуль category. Создание базы данных для всех разделов
Создадим таблицу category и создаем раздел "статьи" и 3 вложенных категории.
-- -- Структура таблицы `category` -- CREATE TABLE IF NOT EXISTS `category` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(300) NOT NULL, `parent_id` int(11) DEFAULT NULL, `position` mediumint(5) DEFAULT NULL, `meta_title` varchar(300) DEFAULT NULL, `meta_h1` varchar(300) DEFAULT NULL, `meta_description` text, `meta_keywords` text, `meta_url` varchar(130) DEFAULT NULL, `content` text, `image` varchar(255) DEFAULT NULL, `template` varchar(50) DEFAULT NULL, `post_status` tinyint(1) DEFAULT NULL, PRIMARY KEY (`id`), KEY `parent_id` (`parent_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ; -- -- Дамп данных таблицы `category` -- INSERT INTO `category` (`id`, `name`, `parent_id`, `position`, `meta_title`, `meta_h1`, `meta_description`, `meta_keywords`, `meta_url`, `content`, `image`, `template`, `post_status`) VALUES (1, 'Статьи', 0, 0, NULL, NULL, NULL, NULL, 'articles', 'Это наш новый раздел статьи
', '/assets/category/smile-macbook.jpg', NULL, 1), (2, 'Первый раздел', 1, 0, NULL, NULL, NULL, NULL, 'first', 'Первый подраздел статей
', '/assets/category/smile-macbook.jpg', NULL, 1), (3, 'Второй раздел', 1, 0, NULL, NULL, NULL, NULL, 'second', 'Второй подраздел статей
', '/assets/category/smile-macbook.jpg', NULL, 1), (4, 'Третий раздел', 1, 0, NULL, NULL, NULL, NULL, 'third', 'Третий подраздел статей
', '/assets/category/smile-macbook.jpg', NULL, 1);
Создание структуры модуля категории для движка на CI3
Отлично! У нас есть таблица для категорий - она не сильно отличается от таблицы pages. Разница как вы уже заметили в дополнительном поле parent_id - так мы сможем задавать родителя для категории и создавать сколько угодно уровней вложенности.
Создадим папку category в modules + вложенные папки controllers, models, config.
Исходный код контроллера будет немного сложнее его предшественника модуля страниц. Давайте займемся подготовкой и для начала расширим нашу главную библиотеку main_lib.php новыми функциями: pagination, short_content, substrword. Допишем в конец файла /modules/common/libraries/main_lib.php следующий код
pagination - конфигурация для отображения и вывода пагинации в разделах. Стили заданные в функции готовы для вывода красиво оформленного блока с ссылками на уровень категории. В первой переменной per_page - можно задать с каким количеством страниц(pages) модулю следует работать.
short_content - вот это действительно интересная функция. Я немного расширил ее код, забегая на перед для работы с будущими модулями, но вкратце объясню логику работы:
С параметром $text - мы передаем функции содержание ячейки content таблицы pages. В базе храниться полное содержание страницы и нам нужно удалить все html теги, затем укоротить текст и вывести это все в категорию.
Зачем же тогда там еще два дополнительных параметра $position и $more_tag? В первом параметре мы указываем сколько символов следует оставить для вывода краткого содержания страницы. Если этот параметр не задан - то обрезаем текст до 400 символов, иначе указываем нужное нам число. А функция substword - обрабатывает текст и добавляет троеточие в конце текста для красивого оформления.
Третий параметр позволяет выводить весь текст до заданного нами тега. Работая с движками joomla и Wordpress вы наверняка обращали внимание на кнопку "Подробнее..." или "Разрыв статьи", в разных версиях по разному. Так вот текстовые редакторы типа TinyMCE по нажатию на эту кнопку вставляют закомментированный тег, в нашем случае - это . Скрипт находит в тексте данный кусок и обрезает все символы после указателя, далее текст так же обрабатывается и выводится в разделе. Скриншот для подробного разъяснения:
Великолепная вещь, не правда ли? ;-)
Идем дальше и подготовим модель с запросами к бд для модуля категорий.
class Category_model extends CI_Model {
function __construct()
{
parent::__construct();
}
//Функция выбирает каталог по meta_url
function get_category_by_url($url)
{
$result = $this->db->where('meta_url', $url)->get('category')->row_array();
return $result;
}
//выбираем все дочерние категории
function get_child_categories($category_id){
$result = $this->db->where('parent_id', $category_id)->where('post_status', 1)->get('category')->result_array();
return $result;
}
//выборка всех страниц данного каталога для пагинации
function get_all_category_page($num, $offset, $catalog_id = null){
$this->db->select('*');
if ($catalog_id != null){
$this->db->where('cat_id', $catalog_id);
}
$this->db->where('post_status', 1);
$this->db->order_by("pages.edited", "DESC");
$result = $this->db->get("pages", $num, $offset)->result_array();
return $result;
}
//Подсчет количества страницы категории по id для пагинации
public function count_category_pages($id){
$this->db->where('cat_id', $id);
$this->db->from('pages');
$result = $this->db->count_all_results();
return $result;
}
}
Стандартная работа active records. Получаем данные отдельной категории или выбираем все дочерние категории указывая parent_id в запросе. Для постраничной навигации нам следует задать указатель начала выборки и количество элементов для вывода. Если мы находимся на 3й странице то необходимо показать элементы с 11 по 15. Эти параметры мы и будем передавать из нашего контроллера category.php Подсчет страниц раздела - так же необходим для постраничной навигации, что бы рассчитать количество страниц для вывода.
Создание пагинации на codeigniter 3 + bootstrap. Исходный код контроллера category.php
Что бы наш движок полноценно функционировал и мы могли выводить адрес сайта и работать с url'ами - подключим в автозагрузку помощник url. Открываем файл /application/config/autoloader.php и добавляем в массив автозагрузки helper - помощник "url"
$autoload['helper'] = array('url');
Ну вот мы и приблизились к моменту истины данного урока. Следующий код я постарался хорошо закомментировать, что бы вам было легче разобраться. В место двух привычных методов класса category мы будем использовать три. Почему? ДА все из за постраничной навигации;) Код немного сложный, я постарался оптимизироваться запросы к бд до минимума, полный вывод категории использует всего 8 запросов - все запросы и время генерации страницы и затрачиваемое время на работу с бд можно посмотреть включив profiler в конструкторе библиотеки main_lib.
class Category extends MX_Controller {
var $module_name = "category";
function __construct()
{
parent::__construct();
$this->load->library('common/main_lib');
$this->load->model('category_model');
}
function index(){
show_404();
}
//вывод всех статей в разделе статьи или вывод одной статьи
function view($url = null){
//проверяем существует ли раздел
$this->main_lib->check_isset_page($url, 'category');
//выбираем все данные о категории
$category = $this->category_model->get_category_by_url($url);
//выводим 404 если страница отключена
if($category['post_status'] == '0'){
show_404();
}
//Определяем массив с мета данными текущей категории
$data = $this->main_lib->get_meta_data($url, 'category');
//Формируем содержание категории
$data["content"] = $this->get_category($category);
//выводим раздел
$this->main_lib->render_main_page($data);
}
//вывод сгенерированного содержания страницы для общего шаблона по url
function get_category($category){
//выбираем все страницы раздела и делаем пагинацию
$data_pages_links = $this->get_category_pages_links($category);
//помещаем в массив данные всех страниц раздела
$category["pages"] = $data_pages_links['pages'];
//помещаем в массив данные о навигации раздела
$category['links'] = $data_pages_links['links'];
//выбираем все дочерние категории
$category["categories"] = $this->category_model->get_child_categories($category['id']);
//проверяем не задан ли шаблон для этой страницы
$category['template'] != '' ? $template = $category['template'] : $template = "category_full.tpl";
$data = $this->load->view("site/".$template, $category, true);
return $data;
}
function get_category_pages_links($category)
{
//загружаем библиотеку пагинация
$this->load->library('pagination');
//подключаем конфигурацию пагинации bootstrap
$config = $this->main_lib->pagination();
//задаем путь раздела для навигации
$config["base_url"] = base_url().'category/'.$category['meta_url'].'/';
//задаем какой сегмент url определяет текущий уровень
$config["uri_segment"] = 3;
//подсчитываем общее число страниц в разделе для генерации уровней пагинации
$config['total_rows'] = $this->category_model->count_category_pages($category['id']);
//выбираем текущее положение пагинации по url или оставим пустой
$uri_segment = ($this->uri->segment(3)) ? $this->uri->segment(3) : 0;
//делаем выборку всех страниц для текущего раздела с учетом текущего уровня
$pages = $this->category_model->get_all_category_page($config["per_page"], $uri_segment, $category['id']);
//если страницы существуют, подготавливаем краткое содержание страницы используем функцию общей библиотеки
if (!empty($pages)){
for($i=0; $imain_lib->short_content($pages[$i]['content']);
}
}
//инициализируем постраничную навигации
$this->pagination->initialize($config);
//создаем список ссылок для перехода
$data['links'] = $this->pagination->create_links();
//возвращаем массив страниц для вывода в категории
$data['pages'] = $pages;
return $data;
}
}
Перечислять все наши действия - повторяться с комментариями, но вкратце пройдемся:
- Проверяем наличие страницы в бд и если такой раздел существует получаем все данные по url
- методом get_category - генерируем содержание $content для вывода в главном шаблоне
- Get_category_pages_links - не только подготавливает и запускает библиотеку pagination встроенную в codeigniter - но так же делает выборку всех страниц категории. Так же мы проходимся циклом по нашему массиву с выбранными данными и генерируем краткое содержание каждой отдельной страницы.
- Инициализируем постраничную навигацию и возвращаем данные
- Элемент links массива $category - содержит в себе сгенерированное отображение постраничной навигации.
- Элемент categories - содержит в себе список с данными всех дочерних категорий
- Элемент pages - данные всех страниц отображаемого раздела
- Генерируем все данные в шаблоне category_full.tpl
- Отдаем данные на рендинг главного шаблона
Продолжаем работать с созданным ранее на фреймворке bootstrap сайтом и создадим шаблон category_full.tpl
Здесь мы выводим заголовок раздела. Далее проверяем существуют ли у данного раздела дочерние категории, если да, то циклом с красивым оформлением - выводим.
Далее - уведомляем пользователя о том что в категории нет страниц, либо выводим циклом все страницы раздела, задавая ссылки на саму страницу, изображение или заглушку, краткое содержание и заголовок.
В самом конце - изображение раздела и его описание.
Теперь наполним немного наш сайт пустыми тестовыми страницами, указав родительскую категорию - наш главный раздел "Статьи".
INSERT INTO `pages` (`id`, `name`, `cat_id`, `image`, `content`, `meta_title`, `meta_h1`, `meta_description`, `meta_keywords`, `meta_url`, `template`, `created`, `edited`, `post_status`, `short_content`, `author`, `post_viewed`) VALUES (3, 'Еще одна страница', 1, NULL, 'Содержание еще одной страницы
', NULL, NULL, NULL, NULL, 'second2', NULL, '2015-11-06 23:22:55', '2015-11-06 23:23:00', 1, NULL, 'Евгений Поляков', '1'), (4, 'Еще одна страница', 1, NULL, 'Содержание еще одной страницы
', NULL, NULL, NULL, NULL, 'second3', NULL, '2015-11-06 23:22:55', '2015-11-06 23:23:00', 1, NULL, 'Евгений Поляков', '1'), (5, 'Еще одна страница', 1, NULL, 'Содержание еще одной страницы
', NULL, NULL, NULL, NULL, 'second4', NULL, '2015-11-06 23:22:55', '2015-11-06 23:23:00', 1, NULL, 'Евгений Поляков', '1'), (6, 'Еще одна страница', 1, NULL, 'Содержание еще одной страницы
', NULL, NULL, NULL, NULL, 'second5', NULL, '2015-11-06 23:22:55', '2015-11-06 23:23:00', 1, NULL, 'Евгений Поляков', '1'), (7, 'Еще одна страница', 1, NULL, 'Содержание еще одной страницы
', NULL, NULL, NULL, NULL, 'second6', NULL, '2015-11-06 23:22:55', '2015-11-06 23:23:00', 1, NULL, 'Евгений Поляков', '1'), (8, 'Еще одна страница', 1, NULL, 'Содержание еще одной страницы
', NULL, NULL, NULL, NULL, 'second7', NULL, '2015-11-06 23:22:55', '2015-11-06 23:23:00', 1, NULL, 'Евгений Поляков', '1'), (9, 'Еще одна страница', 1, NULL, 'Содержание еще одной страницы
', NULL, NULL, NULL, NULL, 'second8', NULL, '2015-11-06 23:22:55', '2015-11-06 23:23:00', 1, NULL, 'Евгений Поляков', '1'), (10, 'Еще одна страница', 1, NULL, 'Содержание еще одной страницы
', NULL, NULL, NULL, NULL, 'second9', NULL, '2015-11-06 23:22:55', '2015-11-06 23:23:00', 1, NULL, 'Евгений Поляков', '1'), (11, 'Еще одна страница', 1, NULL, 'Содержание еще одной страницы
', NULL, NULL, NULL, NULL, 'second10', NULL, '2015-11-06 23:22:55', '2015-11-06 23:23:00', 1, NULL, 'Евгений Поляков', '1'), (12, 'Еще одна страница', 1, NULL, 'Содержание еще одной страницы
', NULL, NULL, NULL, NULL, 'second11', NULL, '2015-11-06 23:22:55', '2015-11-06 23:23:00', 1, NULL, 'Евгений Поляков', '1'), (13, 'Еще одна страница', 1, NULL, 'Содержание еще одной страницы
', NULL, NULL, NULL, NULL, 'second12', NULL, '2015-11-06 23:22:55', '2015-11-06 23:23:00', 1, NULL, 'Евгений Поляков', '1');
Последний скриншот - это результат нашей с вами работы во всей ее красе) Как мы видим все дочерние разделы выводятся, все статьи раздела отображаются, пагинация работает а сайт уже похож на полноценный блог. У кого возникли проблемы - может скачать исходный код полностью рабочего движка на codeigniter3 + hmvc
Спасибо за внимание и как всегда жду ваших отзывов.
Євген
Ого, так скоро не чекав :) Дуже дякую, що додаєте код, бо не завжди все виходить з першого разу, а там можна все перевірити. Чи будемо розглядати галерею і адмінку?
Евгений Поляков
Да, стараюсь писать когда выпадает свободное время. Галерея и админка для идентичного движка есть и даже больше... Конечно будем писать статьи и расписывать где что лежит, там уже совершенно другой уровень будет;) Нужно предварительно подготовить базу всего движка и потом создавать admin.php в модулях и напишем статьи со временем.