CakePHP и простой поиск по сайту

Полнотекстовый поиск — слишком сложно для нашего маленького сайта, но в тоже время мы хотим его сделать достаточно рабочим. Первый вариант — в контроллере поиска обозначить все модели, по которым мы будем проводить поиск, и последовательно дергать их. Но это сразу неинтересно, особенно если мы уже ввели какой-то массив главных контроллеров ($_CONTROLLERS). Также для этого массива мы можем ввести поля, по которым проводить поиск — и собственно готово. Вариант 1.

<?php
class SearchController extends AppController {
	var $name = 'Search';
	var $uses = array();
	var $cacheAction = false;
	var $_fields = array('title', 'intro', 'desc', 'sidebar', 'email', 'city', 'address');
	function index() {
		$search = isset($_GET['search']) ? $_GET['search'] : '';
		$search = trim(str_replace(array("'", '"'), "", strip_tags($search)));
		if (strlen($search) < 3) {
			$this->Session->setFlash(__('Search query is too short', true), null, null, 'error');
			$this->redirect('/');
		}
		$tmp= explode(' ', $search);
		$search = array();
		foreach ($tmp AS $word) {
			if ($word) $search[] = $word;
		}
		global $_CONTROLLERS;
		foreach ($_CONTROLLERS AS $controller) {
			$modelName = Inflector::classify($controller);
			App::import('Model', $modelName);
			$model = new $modelName();
			$conditions = array();
			foreach ($this->_fields AS $_field){
				if (isset($model->_schema[$_field])) {
					$tmp = '';
					foreach ($search AS $word) {
						if ($tmp) $tmp .= ' AND ';
						$tmp .= ' LOWER(' . $modelName . '.' . $_field . ') LIKE LOWER(\'%' . $word. '%\')';
					}
					$conditions[] = $tmp;
				}
			}
			$tmp = $model->find('all', array('conditions' => array('OR'=>$conditions)));
			if ($tmp) {
				$this->data[$controller] = $tmp;
			}
		}
		$this->set('search', $search);
	}
}
?>

Все логично и просто, кроме одного но — поиск неправильный) Фактически работает поиск нескольких слов только в одном поле т.е. все поисковые слова должны быть или в заголовке, или в описании. Поэтому мы модифицируем алгоритм построения условий по принципу декартового множества от подусловий.

$tmps       = array();
foreach ($this->_fields AS $_field){
	if (isset($model->_schema[$_field])) {
		foreach ($search AS $word) {
			$tmps[$word][] = ' LOWER(' . $modelName . '.' . $_field . ') LIKE LOWER(\'%' . $word. '%\')';
		}
	}
}
$conditions = array_shift($tmps);
if ($tmps) {
	foreach ($tmps AS $word => $word_conds) {
		$step_next = array();
		foreach ($word_conds AS $word_cond) {
			foreach ($conditions AS $cond) {
				$step_next[] = $cond . ' AND ' . $word_cond;
			}
		}
		$conditions = $step_next;
	}
}

Теперь все правильно и работает, но в русском языке поиск это не только проверки, но и выделение корня. Вариант 2 — с выделением корней — скоро на телеэкранах.

Оставить комментарий

XHTML: Вы можете использовать такие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">