Yii: Добавляем "Поиск по сайту", используя только Yii
Ранее мы добавили на наш сайт календарь на месяц по статьям. Теперь организуем один из самых важных компонентов любого сайта - механизм поиска статей (постов, материалов). Сейчас мы будем делать поиск по сайту только средствами Yii, также можно делать поиск с помощью библиотеки Zend_Search_Lucene - об этом читайте в статье Yii: Делаем поиск по сайту, используя Zend Lucene.
Поехали. Традиционно начинаем с конца. Добавляем в шаблон вызов несуществующего ещё виджета (компонента) SiteSearch:
<?php $this->widget('SiteSearch'); ?>
Дальше создаём этот компонент protected/components/SiteSearch.php:
<?php
class SiteSearch extends CWidget
{
public function run()
{
$form = new SiteSearchForm();
$this->render('siteSearch', array('form'=>$form));
}
}
Здесь есть обращение к форме и виду. Создаём вид /protected/components/views/siteSearch.php:
<div id="search">
<div id="search_div">
<h3>Поиск по сайту</h3>
<?php $url = $this->getController()->createUrl('material/search'); ?>
<?php echo CHtml::beginForm($url); ?>
<div class="row">
<?php echo CHtml::activeTextField($form,'string') ?>
<?php echo CHtml::error($form,'string'); ?>
<?php echo CHtml::SubmitButton('Поиск'); ?>
</div>
<?php echo CHtml::endForm(); ?>
</div>
<div id="SearchFooter"></div>
</div>
Теперь создадим модель формы поиска (в ней только одно поле) /protected/models/SiteSearchForm.php:
<?php
class SiteSearchForm extends CFormModel
{
public $string;
public function rules() {
return array(array('string', 'required'));
}
public function safeAttributes() {
return array('string',);
}
}
В контроллер с постами (статьями, материалами) добавляем ещё один метод:
public function actionSearch()
{
$search = new SiteSearchForm;
if(isset($_POST['SiteSearchForm'])) {
$search->attributes = $_POST['SiteSearchForm'];
$_GET['searchString'] = $search->string;
} else {
$search->string = $_GET['searchString'];
}
$criteria = new CDbCriteria(array(
'condition' => 'status='.Material::STATUS_PUBLISHED.' AND content LIKE :keyword',
'order' => 'create_time DESC',
'params' => array(
':keyword' => '%'.$search->string.'%',
),
));
$materialCount = Material::model()->count($criteria);
$pages = new CPagination($materialCount);
$pages->pageSize = Yii::app()->params['materialsPerPage'];
$pages->applyLimit($criteria);
$materials = Material::model()->findAll($criteria);
$this->render('found',array(
'materials' => $materials,
'pages' => $pages,
'search' => $search,
));
}
А также в нём разрешаем этот метод всем посетителям сайта:
public function accessRules()
{
return array(
array('allow', // allow all users to access 'index' and 'view' actions.
'actions'=>array('index','view','postedinmonth','postedondate','search'),
'users'=>array('*'),
),
...
И вид /protected/views/found.php
<?php if(!empty($_GET['tag'])): ?>
<h1>Materials Tagged with <i><?php echo CHtml::encode($_GET['tag']); ?></i></h1>
<?php endif; ?>
<?php if(!empty($search->string)): ?>
<h1>Materials Searched by <i><?php echo CHtml::encode($search->string); ?></i></h1>
<?php endif; ?>
<?php foreach($materials as $material): ?>
<?php
$pizza = explode('>', $material->content);
$s = '';
for ($i = 0; $i < count($pizza); $i++) {
$piece = explode('<', $pizza[$i]);
$replace = preg_replace('/('.$search->string.')/i', '<b><span style="background:yellow;">${1}</span></b>', $piece[0]);
if (count($piece) == 2) {
$s .= $replace.'<'.$piece[1].'>';
} else if (count($piece) == 1) {
$s .= $replace;
}
}
$material->content = $s;
$this->renderPartial('_view',array(
'data'=>$material,
));
?>
<?php endforeach; ?>
<br/>
<?php $this->widget('CLinkPager',array('pages'=>$pages)); ?>
После введения запроса и нажатия кнопки Поиск, посетитель переводится на url - /material/search
almix
Разработчик Loco, автор статей по веб-разработке на Yii, CodeIgniter, MODx и прочих инструментах. Создатель Team Sense.
Вы можете почитать все статьи от almix'а.
- 14 Разработка приложения на Yii. Урок 14: Выводим список категорий как новый виджет на сайте (29.04.2015)
- 13 Разработка приложения на Yii. Урок 13: Внедряем категории для статей. (29.04.2015)
- 12 Разработка приложения на Yii. Урок 12: Профилирование приложения, включаем кеширование. (20.01.2015)
- 11 Yiico. Видеокурс по разработке сайта на Yii. Урок 11: Отладка приложения, включаем журналирование. (20.01.2015)
- 10 Yiico. Видеокурс по разработке сайта на Yii. Урок 10: Если ваше приложение находится не в корневой папке, а во вложенной. (19.10.2014)
- 9 Разработка сайта на Yii с нуля. Урок 9. Выборка статей определённого автора. (13.08.2014)
- 8 Разработка сайта на Yii с нуля. Урок 8. Вызов в моделях функции, общей для них. Как избегать дублирования кода? (25.07.2014)
- 7 Разработка сайта на Yii с нуля. Урок 7. Изменение количества выводимых записей на странице в CGridView. Включаем сессии Yii. (04.09.2013)
- 6 Разработка сайта на Yii с нуля. Урок 6. Автоматич. отправка оповещений об одобренных комментариях на email автора комментария (11.08.2013)
- 5 Разработка сайта на Yii с нуля. Урок 5. Переименовываем blog в yiico. Изменяем "Home" в breadcrumbs. Включаем Gzip-сжатие. (09.08.2013)
- 4 Курс по Yii с нуля. Урок 4. Дорабатываем простую работу с пользователями: хранение пароля при редактировании пользователя. (13.04.2013)
- 3 Курс по Yii с нуля. Урок 3. Создаём новых пользователей. Организуем простую систему авторизации. Аутентификация, пароли, соли. (20.07.2014)
- 2 Yii + Git (github) на Mac. (24.03.2013)
- 2 Курс по Yii с нуля. Урок 2. Переносим и настраиваем Yii и проект нашего сайта на рабочем сервере. Избавляемся от index.php в url (09.07.2014)
- 1 Курс по Yii с нуля. Урок 1. Устанавливаем Yii на локальном компьютере. Заводим проект будущего сайта. (10.03.2013)
- 0 Composer – пакетный менеджер PHP. Что и как? (22.07.2014)
- 0 MySQL: проверить содержится ли значение в поле столбца (в столбце хранится строка значений через запятую) (22.05.2014)
- 0 Yii: Статичные страницы (создание, редактирование, удаление) (28.04.2014)
- 0 Yii: Расширение ECKEditor = Связка ckeditor + kcfinder (визуальный редактор с бесплатным файловым менеджером) (28.04.2014)
- 0 Yii: Bootstrap tabs, делаем активной вкладку на которую выполняется переход по ссылке (20.03.2014)
- 0 Yii: Доступ к атрибуту модели из файла шаблона (Вызов в шаблоне какого-либо атрибута модели). (17.02.2014)
- 0 Yii: Множественный автокомплит с помощью CJuiAutoComplete (автокомплит нескольких значений в одно поле) (07.02.2014)
- 0 Yii: Фотогалерея через поведение (доработка расширения imagesgallerymanager) (08.03.2016)
- 0 Yii: Установка и настройка Yii-app заготовки приложения от Crisu83 (09.03.2014)
- 0 Twitter Bootstrap Carousel Crossfade (09.09.2013)
24 комментариев
В самом начале написано "Добавляем в шаблон вызов несуществующего ещё виджета (компонента) SiteSearch: <?php $this->widget('SiteSearch'); ?> " В какой именно файл мне нужно вставить эту строчку кода?
almix: в шаблон, в layouts какой-нибудь, у меня это column3.php
Артём, вы точно задали $pages->pageSize = Yii::app()->params['materialsPerPage']; ?
materialsPerPage устанавливаю в config/params
В экшне Search добавил ограничение на длину строки запроса. Значение указал в params.
if (strlen($search->string) < Yii::app()->params->minSearchStringLength) {
$this->render('invalidRequest');return;
}
Ну и виде при нулевом результате:
<?php if (!$materials) {
echo "Ничего не найдено";
} ?>
Спасибо! Сделал без создания доп. вида invalidRequest и использовал mb_strlen вместо strlen, а то русские символы не правильно по длине ограничиваются:
<?php if (mb_strlen($search->string, 'UTF-8') < Yii::app()->params->minSearchStringLength) {echo "Слишком короткий запрос. Надо не меньше ".Yii::app()->params->minSearchStringLength." символов.";
return;
}?>
<?php if (!$materials) {
echo "Ничего не найдено.";
} ?>
Лёня -> контроллер actionSearch, допишите в запросе
'condition' => 'status='.Material::STATUS_PUBLISHED.' AND content LIKE :keyword', что-то типа 'OR title LIKE :keyword'
Сделал все по статье.
При вставке в лейаут который рендерю в main перестает работать(запрос отправляется по другому адресу).
В чем может быть проблема?
Работает всё хорошо, но а если понадобится сделать поиск не по одной модели, а по всему сайту, а там же ведь есть и не связанные таблицы. К примеру как найти в этих таблицах:
PHP warning
include(Material.php): failed to open stream: No such file or directory
privet, atkuda nayti etot fayl..?
Вставлять $search->string прямо в preg_replace - не очень-то хорошая идея.
P.S. Это будет поиск по одному разделу (только по Material), но почти таким же образом можно сделать поиск по всему сайту.