Приветствую всех новых гостей моего сайта а особенно постоянных читателей серии статей по созданию движка на 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 в модулях и напишем статьи со временем.