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