Программирование, веб-кодинг, Расширения, виджеты

Поиск по сайту в Yii2 (через расширение с Zend Lucene)

Настраиваем поиск по модели блога Blog

Поиск по сайту в Yii2 (через расширение с Zend Lucene)

Для механизма поиска используем расширение Yii2 Zend Lucene Search Component V2

Устанавливаем его через composer.

Могут быть ошибки, что не находятся нужные версии. У меня всё подтянулось с такими строками в сcmposer.json

<span>"zendframework/zendsearch": "2.0.0rc5",
"zendframework/zend-stdlib": "2.3.1 as 2.0.0rc5",
"himiklab/yii2-search-component-v2": "*"</span>

Добавляю в конфиг для консоли в массив components (это config/console.php)

'search' => [
    'class' => 'himiklab\yii2\search\Search',
    'models' => [
        'app\models\Blog',
    ],
],

и его же добавляю в конфиг самого приложения (config/web.php).

в папке commands создаю контроллер SearchController.php для вызова через консоль, чтобы создать поисковый индекс по классу Blog

<?php 
namespace app\commands;
use Yii;
use yii\console\Controller;

class SearchController extends Controller
{
 // Of course, this function should be in the console part of the application!
    public function actionIndexing()
    {
       /** @var \himiklab\yii2\search\Search $search */
        $search = Yii::$app->search;
        $search->index();
    }
}

в UrlManager -> rules мне пришлось добавить правило для вызова действия поиска после ввода запроса. Иначе роуты конфликтуют с другими

'blog'=>'blog/index', 
'blog/create'=>'blog/create',
<strong>'blog/search'=>'blog/search',</strong>
'blog/<section:\w+>'=>'blog/index',
'blog/<tag:\w+>'=>'blog/index',

Вот это действие, добавляю его в контроллер BlogController.php

public function actionSearch($q = '')
    {
        /** @var \himiklab\yii2\search\Search $search */
        $search = Yii::$app->search;
        $searchData = $search->find($q); // Search by full index.
        //$searchData = $search->find($q, ['model' => 'page']); // Search by index provided only by model `page`.

        $dataProvider = new ArrayDataProvider([
            'allModels' => $searchData['results'],
            'pagination' => ['pageSize' => 10],
        ]);

        return $this->render(
            'found',
            [
                'hits' => $dataProvider->getModels(),
                'pagination' => $dataProvider->getPagination(),
                'query' => $searchData['query']
            ]
        );
    }

также ему понадобилось подключить вверху этого контроллера строку

use yii\data\ArrayDataProvider;

в модели models/Blog подключаю поведение

use himiklab\yii2\search\behaviors\SearchBehavior;

и в массив поведений добавляю 'search'

public function behaviors()
    {
        return [
            ...
        'search' => [
                'class' => SearchBehavior::className(),
                'searchScope' => function ($model) {
                    /** @var \yii\db\ActiveQuery $model */
                    $model->select(['title', 'text', 'id', 'alias']);
                    //$model->andWhere(['indexed' => true]);
                },
                'searchFields' => function ($model) {
                    /** @var self $model */
                    return [
                        ['name' => 'title', 'value' => $model->title],
                        ['name' => 'body', 'value' => strip_tags($model->text)],
                        ['name' => 'url', 'value' => '/blog/'.$model->id.'-'.$this->alias, 'type' => SearchBehavior::FIELD_KEYWORD],
                        // ['name' => 'model', 'value' => 'page', 'type' => SearchBehavior::FIELD_UNSTORED],
                    ];
                }
            ],
        ];
    }

копирую целиком из папки расширения yii2-search-component-v2 модуль search в корневую папку с модулями /modules (если её нет, то создаю её)

в нужном месте вида вставляю окно поиска

<?= $this->render('_search_form', ['text' => '']) ?>

_search_form.php создаю в этой же папке где лежит сей вид. Вот содержимое _search_form.php

<?php
use yii\helpers\Html;
use yii\helpers\Url;
?>

<?= Html::beginForm(Url::to(['/blog/search']), 'get', ['class' => 'form-inlin']) ?>
        <div class="input-group">
          <?= Html::textInput('q', $text, ['class' => 'form-control', 'placeholder' => 'Поиск...']) ?>
          <span class="input-group-btn">
            <?= Html::submitButton('<i class="glyphicon glyphicon-search"></i>', ['class' => 'btn btn-primary']) ?>
          </span>
        </div><!-- /input-group -->
<?= Html::endForm() ?>
<br/>

и вот содержимое файла вида found.php с результатами поиска

use yii\helpers\Html;

$query = yii\helpers\Html::encode($query);

$this->params['breadcrumbs'][] = ['label' => 'Блог', 'url' => ['/blog']];
$this->title = "Результаты поиска по запросу \"$query\"";
$this->params['breadcrumbs'][] = $this->title;

app\modules\search\SearchAssets::register($this);
$this->registerJs("jQuery('.search').highlight('{$query}');");
?>

<div class="row">
    <div class="col-md-6 col-md-offset-2">
        
        <?php
        if (!empty($hits)):
            foreach ($hits as $hit):
                ?>
                <h3><a href="<?= yii\helpers\Url::to($hit->url, true) ?>"><?= $hit->title ?></a></h3>
                <p class="search"><?= $hit->body ?></p>
                <hr />
            <?php
            endforeach;
        else:
            ?>
            <div class="alert alert-danger"><h3>По запросу "<?= $query ?>" ничего не найдено!</h3></div>
        <?php
        endif;

        echo yii\widgets\LinkPager::widget([
            'pagination' => $pagination,
        ]);
        ?>
        
        
    </div>
    <div class="col-md-3">
        
        <?= $this->render('_search_form', ['text' => "{$query}"]) ?>
        
        <?= app\components\SectionsWidget::widget() ?>
        <hr>
        <?= app\components\TagsWidget::widget() ?>
    </div>
</div>

Вот и всё.

Чтобы поиск давал результаты, надо через консоль выполнить команду

./yii search/indexing

Вот что должно быть видно в консоли (при команде ./yii выполненной в папке проекта вы увидите, что появилась доступная команда search/indexing)


Аматизировать создание поискового индекса с помощью КРОНа

Далее, чтобы периодически не выполнять эту команду вручную по мере публикации новых статей, удобно автоматизировать её вызов с помощью КРОН на хостинге. Например, задайте в КРОНе вызов

sh $HOME/inspire2/makesearchindex.sh

один раз в сутки. Создайте в корневой папке этот файл makesearchindex.sh с содержимым

#!/bin/bashcd 
$HOME/inspire2
./yii search/indexing



Возможные ошибки

1. Если будет ошибка

Exception 'yii\base\UnknownPropertyException' with message 'Getting unknown property: yii\console\Application::search'

значит в компонентах консоли не указали компонент 'search' или в нём пути к классу или модели.


2. При вводе запроса и нажатии кнопки поиска такая ошибка

Getting unknown property: yii\web\Application::search

Значит забыли добавить в конфиг приложения компонент 'search'