Як зробити FULLTEXT пошук у CMS на CodeIgniter

На Хабре останнім часом з'являється все більше постів присвячених набираючому популярності framework'у CodeIgniter. Це досить простий і зручний фреймворк, за допомогою якого можна швидко почати робити нормальні програми на PHP. Під катом приклад реалізації FULLTEXT пошуку у CMS на CodeIgniter.

1. Підготовка CodeIgniter.

Завантажуємо та розпаковуємо дистрибутив CodeIgniter в якусь папку на вашому сервері. Створюємо базу даних, користувача з правами доступу до цієї БД та прописуємо налаштування підключення до application/config/database.php. Відкриваємо application/config/config.php та виставляємо налаштування поля base_url.

2. Налаштування бази даних.

БД ми вже створили у першому кроці, але ми не маємо таблиць. Створимо просту таблицю pages.

CREATE TABLE pages ( >int (10) UNSIGNED NOT NULL AUTO_INCREMENT, URL text NOT NULL , title text NOT NULL , content text NOT NULL , updated datetime NOT NULL , PRIMARY KEY (id), FULLTEXT KEY content (content) ) ENGINE=MyISAM

* Цей source code був highlighted with Source Code Highlighter.

При використанні FULLTEXT необхідно вказати всі поля, за якими ми будемо шукати. У цій таблиці пошук проводитиметься лише по полю content. Зверніть увагу, що пошук FULLTEXT працює тільки з використанням MyISAM engine.

3. Тестові дані

Для тестування нашого пошукового механізму до таблиці необхідно додати кілька тестових даних. Я вирішив, що Вікіпедія може стати хорошим донором для нашої БД. Я написав невеликий скрипт, який бере кілька останніх статей і потім за допомогою експорту Вікіпедії заносить ці статті до БД.4. Пошук по базіДля пошуку ми будемо використовувати SQLзапит виду:

SELECT * FROM pages WHERE MATCH (content) AGAINST ( 'test') > 0

* Цей source code був highlighted with Source Code Highlighter.

При використанні FULLTEXT пошуку необхідно пам'ятати кілька обмежень.

  • Довжина запиту має перевищувати 3 символи, інакше пошук поверне порожній результат.
  • Існує набір стоп слів, який MySQL ігнорує при пошуку ('the', 'however', 'hello'). Якщо ви спробуєте шукати за цими словами, результат пошуку буде пустим.
  • Також доступний розширений пошук. Повну інформацію можна знайти у документації до MySQL.

5. CodeIgniter та MVC патерн.

Повернемося до нашого фреймворку. CodeIgniter надає популярний патерн проектування модель-вид-контролер (MVC model-view-controller). Нагадаю основні правила:

  • Усі зміни та робота з БД проводитися з моделі
  • Нічого не може бути виведено користувачеві з контролера або моделі
  • Тільки один вираз може бути всередині тегів скорочений запис PHP)
Якщо ви порушуєте якесь із цих правил, то варто повернутися назад і ще раз подумати над структурою вашого проекту. Почнемо розробку пошуку з файлу моделі. Я використовую лише один метод, який виконує пошук. Ви можете помітити, що тут використано "прямий SQL запит", хоча в CodeIgniter є ActiveRecord, що дозволяє спростити формування запитів. Нижче представлений код моделі, що знаходиться в application/models/page_model.php

class Page_model extends Model функція Page_model() parent::Model(); // Робимо доступною БД у всіх функціях $ this ->load->database(); > function search($terms) // Виконання запиту та повернення результату $sql = "SELECT url,title FROM pages WHERE MATCH (content) AGAINST (?) > 0" ; $query = $ this ->db->query($sql, array($terms, $terms)); повернути $query->result(); > ; >

* Цей вихідний код було виділено за допомогою підсвічування вихідного коду.

php $ this- > навантаження- > helper('форма'); ? > php echo form_open ($ this- > uri- > uri_string); ? > php echo form_label ( 'Пошук:' , 'поле пошуку'); ? > php echo form_input ( array ( 'name' = > 'q', ' >> 'search-box', 'value' = > $search_terms)); ? > php echo form_submit ( 'пошук' , 'Пошук'); ? > php echo form_close (); ? > php if ( ! is_null ($ результати )) : ? > php if ( count ($ результати )) : ? > ul > php foreach ($ результати як $ результат) : ? > li > a href ="&# 60 ;? php echo $ result- > url; ? > " > php echo $ result- > назва; ? > a > li > php endforeach ? > ul > php else: ? > p > em > Немає результатів за вашим запитом. em > p > php endif ? > php endif ? >

* Цей вихідний код було виділено за допомогою підсвічування вихідного коду.

class Pages extends Controller function search($search_terms = '' ) // Якщо форма відправлена, перепишем URL, додавши рядок запиту // зверніть увагу, що з деякими символами // можуть бути проблеми. if ($ this ->input->post( 'q' )) redirect( '/pages/search/' . $ this ->input->post( 'q' )) ; > if ($search_terms) // Завантаження моделі та виконання пошуку по БД $ this ->load->model( 'page_model' ); $results = $ this ->page_model->search($search_terms); > // Завантаження виду файлу та виведення на екран $ this ->load->view( 'search_results' , array( 'search_terms' => $search_terms, 'results' => @$results )); > >

* Цей source code був highlighted with Source Code Highlighter.

* Цей source code був highlighted with Source Code Highlighter.

Тепер ми отримали робітничий прототип. Не забудьте, що у вашій БД повинні бути дані (не менше 3 рядків). Тепер наберіть у вашому браузері щось типу 'http://localhost/index.php/pages/search', введіть у рядок пошуку який-небудь текст, що міститься в базі даних, і натисніть пошук. Результат виглядатиме приблизно так:

6. Додавання нових можливостей у наш пошук.

Для початку додамо посторінкову навігацію для результатів пошуку. Для виведення посторінкової навігації в CodeIgniter використовується клас Pagination. Модифікуємо нашу модель для виведення посторінкової навігації. Для цього нам необхідно задати кількість записів, що вибираються з БД, номер запису з якої проводити вибірку, а також отримати загальну кількість записів за цим запитом. Ось що в нас вийшло:

class Page_model extends Model function search($terms, $start = 0, $results_per_page = 0) // Задамо ліміт записів, що вибираються //і стартову позицію if ($results_per_page > 0) > $limit = "LIMIT $start, $results_per_page"; > else $limit = ''; > // Виконання SQL запиту $sql = "SELECT url, title, content FROM pages WHERE MATCH (content) AGAINST(?) > 0 $limit" ; $query = $ this ->db->query($sql, array($terms, $terms)); return $query->result(); > функція count_search_results($terms) // Виконати SQL до count number of search results $sql = "SELECT COUNT(*) AS count FROM pages WHERE MATCH (content ) AGAINST (?) "; $query = $ this->db->query($sql, array($terms)); return $query->row()->count; > >

* Цей source code був highlighted with Source Code Highlighter.

class Pages extends Controller function search($search_terms = '' , $start = 0) // Якщо форма відправлена ​​перепишем URL додавши рядок запиту // зверніть увагу, що з деякими символами // можуть бути проблеми. if ($ this ->input->post( 'q' )) redirect( '/pages/search/' . $ this ->input->post( 'q' )) ; > if ($search_terms) // Визначимо скільки результатів //виводити на сторінку $results_per_page = $ this ->config->item( 'results_per_page' ); // Завантажуємо модель, виконуємо пошук, визначаємо // скільки всього результатів пошуку $ this ->load->model( 'page_model' ); $results = $this ->page_model->search($search_terms, $start, $results_per_page); $total_results = $this ->page_model->count_search_results($search_terms); // Завантаження посторінкової навігації $ this ->_setup_pagination( '/pages/search/' . $search_terms . '/' , $total_results, $results_per_page); // Визначаємо які результати виводити $first_result = $start + 1; $last_result = min($start + $results_per_page, $total_results); > // Завантаження виду та виведення результатів $ this ->load->view( 'search_results' , array( 'search_terms' => $search_terms, 'first_result' => ; @$first_result, 'last_result' => @$last_result, 'total_results' => @$total_results, 'results' => > function _setup_pagination($url, $total_results, $results_per_page) // Не забуваємо завантажити сторінкову навігацію $ this ->load->library( 'pagination' ); $uri_segment = count(explode( '/' ,$url)); // Ініціалізація сторонньої навігації та встановлення // необхідних параметрів $ this ->pagination->initialize(array( 'base_url' => site_url($url), 'uri_segment' => $uri_segment, 'total_rows' => $total_results, 'per_page' => $results_per_page )); > >

* Цей вихідний код було виділено за допомогою підсвічування вихідного коду.

* Цей вихідний код було виділено за допомогою підсвічування вихідного коду.

php $ this- > навантаження- > helper(array('form', 'search')); ? > php echo form_open ($ this- > uri- > uri_string); ? > php echo form_label ( 'Пошук:' , 'поле пошуку'); ? > php echo form_input ( array ( 'name' = > 'q', ' >> 'search-box', 'value' = > $search_terms)); ? > php echo form_submit ( 'пошук' , 'Пошук' ); ? > php echo form_close (); ? > php if ( ! is_null ($ результати )) : ? > php if ( count ($ результати )) : ? > p > Показано результати пошуку для 'php echo $search_terms; ? > ' (php echo $ first_result ; ? > – php echo $ last_result ; ? > of php echo $ total_results ; ? > ): p > ul > php foreach ($результати як $результат) : ? > li > a href ="&# 60 ;? php echo $ result- > url; ? > " > php echo search_highlight ($ result- > title, $search_terms); ? > a > br /> php echo search_extract ($ result- > content, $search_terms); ? > li > php endforeach ? > ul > php echo $ this- > пагінація- > create_links(); ? > php else: ? > p > em > Немає результатів за вашим запитом. em > p > php endif ? > php endif ? >

* Цей вихідний код було виділено за допомогою підсвічування вихідного коду.

А так нові результати пошуку:

7. Ще більше смачних фішок.

CodeIgniter надає можливість виведення тестових даних та різної додаткової інформації. Приміром так можна запустити роботу тесту для моделі:

// Mark start of search $ this ->benchmark->mark( 'search_start' ); // Load the model, розробляє search і establishe total // number of results $ this ->load->model( 'page_model' ); $results = $this ->page_model->search($search_terms, $start, $results_per_page); $total_results = $this ->page_model->count_search_results($search_terms); // Mark end of search $ this ->benchmark->mark( 'search_end' );

* Цей source code був highlighted with Source Code Highlighter.