This plugin provides an easy to install and non-obstrusive solution to add a local search engine to your Cake app.
Features :
- Uses MySQL Full-Text engine.
- Easy install : download the files and create 1 db table, no matter how many Models you want to index.
- Non-obstrusive : you don’t need to add Full-Text indexes on existing tables.
- Several search modes : natural language, natural language with query expansion, and boolean mode.
To install, copy the ‘search’ directory to the ‘plugins’ folder:
git clone git://github.com/kalt/search.git
Or click ‘download’ and copy the content of the zip file into your ‘plugins’ folder.
Create one db table as described in search/config/sql/search.sql
Link any model to the Searchable Behavior, and define the fields you want to index.
class Article extends AppModel
{
var $actsAs = array('Search.Searchable' => array(
'fields' => array('title', 'body')
));
}
That’s it. Whenever you save or edit a record, the ‘title’ and ‘body’ fields will be indexed.
Create a search form anywhere (most of the time in the layout).
The form must contain a text input field named ‘q’.
echo $form->create('Search', array('url' => array(
'plugin' => 'search',
'controller' => 'searches',
'action' => 'index'
)));
echo $form->input('q', array('label' => 'Keywords:'));
echo $form->end();
Create a view to display the paginated search results : {app}/views/plugins/search/searches/index.ctp
Available data :
$q
: Search terms.$data
: Paginated results.
Example:
<h1>Search results</h1>
<p>You searched for: <?php echo $q; ?></p>
<div id="paginator-counter">
<?php echo $paginator->counter(array('format' => "Page %page% on %pages%, %current% results on %count%")); ?>
</div>
<?php foreach($data as $row):
$model_name = key($row);
switch($model_name)
{
case 'Article':
$link = $html->link($row['Article']['title'], array(
'plugin' => null,
'controller' => 'articles',
'action' => 'view',
$row['Article']['id']
));
$description = $row['Article']['body'];
break;
case 'Video':
$link = $html->link($row['Video']['title'], array(
'plugin' => null,
'controller' => 'videos',
'action' => 'play',
$row['Video']['id']
));
$description = $row['Video']['description'];
break;
} ?>
<div class="ressource">
<h2><?php echo $link; ?></h2>
<p align="justify"><?php echo $description; ?></p>
</div>
<?php endforeach; ?>
<div class="paging">
<?php echo $paginator->prev('<< '.__('Previous', true));?>
| <?php echo $paginator->numbers();?>
<?php echo $paginator->next(__('Next', true).' >>');?>
</div>
Two available search modes :
boolean
(default) : MySQL performs a Full-Text boolean search, ie all terms must be in the results.natural
: MySQL performs a Full-Text natural language search, ordering results by relevance.
More info on the Full-Text search functions :
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
To change the search mode, simply add this line in your {app}/config/bootstrap.php
Configure::write('Search.mode', 'natural');
This is an option for the natural language search mode only. More info here :
http://dev.mysql.com/doc/refman/5.0/en/fulltext-query-expansion.html
Defaults to null : it will enable query expansion if the search query is only one word.
To redefine this option, simply add this line in your {app}/config/bootstrap.php
Configure::write('Search.withQueryExpansion', true/false);
If set to false, query expansion will never be used at all, even if the search query is only one word.
If set to true, query expansion will always be used.
By default the allowed chars are alphanumeric only.
To add allowed characters, simply add your own list in your {app}/config/bootstrap.php
Configure::write('Search.allowedChars', array(' '));
Here, the only accepted characters will be alphanumeric and space ’ ’.
Defaults to valid french accents, and space ’ ’.
The default search results URL is /search/searches/search+terms
You can redefine it by adding a simple route in {app}/config/routes.php
Router::connect(
'/search/*',
array('plugin' => 'search', 'controller' => 'searches', 'action' => 'index')
);
Will give you /search/search+terms
If you want to install this plugin in an existing app, with already filled tables, add the 3 following actions in your {app}/app_controller.php
/**
* Builds the search index for the current model based on existing data.
*/
function admin_build_search_index()
{
$this->autoRender = false;
$model =& $this->{$this->modelClass};
if(!isset($model->Behaviors->Searchable))
{
echo "<pre>Error : the {$model->alias} model is not linked with Searchable Behavior.
“;
exit;
}
$data = $model→find(‘all’);
foreach($data as $row)
{
$model→set($row);
$model→Behaviors→Searchable→Search→saveIndex(
$model→alias,
$model→id,
$model→buildIndex()
);
}
echo “
Search index for model {$model→alias} have been built.
”;
}
/**
- Delete the search index for the current model.
*/
function admin_delete_search_index()
{
$this→autoRender = false;
$model =& $this→{$this→modelClass};
if(!isset($model→Behaviors→Searchable))
{
echo “
Error : the {$model→alias} model is not linked with Searchable Behavior.
”;
exit;
}
$model→Behaviors→Searchable→Search→deleteAll(array(
‘model’ => $model→alias
));
echo “
Search index for model {$model→alias} have been deleted.
”;
}
/**
Rebuilds the search index for the current model based on existing data.
*/
function admin_rebuild_search_index()
{
$this→admin_delete_search_index();
$this→admin_build_search_index();
}
You can now go to /admin/{any_controller}/build_search_index
to build the search index based on existing data. Beware, it could take some time, depending on the volume of existing data to index.
Any suggestion is welcome!