Pull to refresh

Cakephp Sphinx behavior

Reading time 8 min
Views 1.7K
По долгу службы мне приходится работать с Cake и Sphinx. Однажды мне надоело делать поиск к сфинксу ручками, и я решил написать небольшой behavior.
Для начала, вам надо положить sphinxapi.php в папку app/vendors. Далее, сохраняем код в файл sphinx.php и кладем в app/models/behaviors.
Собственно код:

Copy Source | Copy HTML
  1. <?php
  2. /**<br/> * Behavior for simple usage of Sphinx search engine<br/> * http://www.sphinxsearch.com<br/> *<br/> * @copyright 2008, Vilen Tambovtsev<br/> * @author  Vilen Tambovtsev<br/> * @license      http://www.opensource.org/licenses/mit-license.php The MIT License<br/> */
  3.  
  4.  
  5. class SphinxBehavior extends ModelBehavior
  6. {
  7.     /**<br/>     * Used for runtime configuration of model<br/>     */
  8.     var $runtime = array();
  9.     var $_defaults = array('server' => 'localhost', 'port' => 3312);
  10.  
  11.     /**<br/>     * Spinx client object<br/>     *<br/>     * @var SphinxClient<br/>     */
  12.     var $sphinx = null;
  13.  
  14.     function setup(&$model, $config = array())
  15.     {
  16.         $settings = array_merge($this->_defaults, (array)$config);
  17.  
  18.         $this->settings[$model->alias] = $settings;
  19.  
  20.         App::import('Vendor', 'sphinxapi');
  21.         $this->runtime[$model->alias]['sphinx'] = new SphinxClient();
  22.         $this->runtime[$model->alias]['sphinx']->SetServer($this->settings[$model->alias]['server'],
  23.                                                            $this->settings[$model->alias]['port']);
  24.     }
  25.  
  26.     /**<br/>     * beforeFind Callback<br/>     *<br/>     * @param array $query<br/>     * @return array Modified query<br/>     * @access public<br/>     */
  27.     function beforeFind(&$model, $query)
  28.     {
  29.         if (empty($query['sphinx']) || empty($query['search']))
  30.             return true;
  31.  
  32.         if ($model->findQueryType == 'count')
  33.         {
  34.             $model->recursive = -1;
  35.             $query['limit'] = 1;
  36.         }
  37.  
  38.         foreach ($query['sphinx'] as $key => $setting)
  39.         {
  40.  
  41.             switch ($key)
  42.             {
  43.                 case 'filter':
  44.                     foreach ($setting as $arg)
  45.                     {
  46.                         $arg[2] = empty($arg[2]) ? false : $arg[2];
  47.                         $this->runtime[$model->alias]['sphinx']->SetFilter($arg[ 0], (array)$arg[1], $arg[2]);
  48.                     }
  49.                    break;
  50.                 case 'filterRange':
  51.                 case 'filterFloatRange':
  52.                     $method = 'Set' . $key;
  53.                     foreach ($setting as $arg)
  54.                     {
  55.                         $arg[3] = empty($arg[3]) ? false : $arg[3];
  56.                         $this->runtime[$model->alias]['sphinx']->{$method}($arg[ 0], (array)$arg[1], $arg[2], $arg[3]);
  57.                     }
  58.                    break;
  59.                 case 'matchMode':
  60.                    $this->runtime[$model->alias]['sphinx']->SetMatchMode($setting);
  61.                    break;
  62.                 case 'sortMode':
  63.                     $this->runtime[$model->alias]['sphinx']->SetSortMode(key($setting), reset($setting));
  64.                     break;
  65.                 default:
  66.                     break;
  67.             }
  68.         }
  69.         $this->runtime[$model->alias]['sphinx']->SetLimits(($query['page'] - 1) * $query['limit'],
  70.                                                            $query['limit']);
  71.  
  72.         $indexes = !empty($query['sphinx']['index']) ? implode(',' , $query['sphinx']['index']) : '*';
  73.  
  74.         $result = $this->runtime[$model->alias]['sphinx']->Query($query['search'], $indexes);
  75.  
  76.         if ($result === false)
  77.         {
  78.             trigger_error("Search query failed: " . $this->runtime[$model->alias]['sphinx']->GetLastError());
  79.             return false;
  80.         }
  81.         else if(isset($result['matches']))
  82.         {
  83.             if ($this->runtime[$model->alias]['sphinx']->GetLastWarning())
  84.             {
  85.                 trigger_error("Search query warning: " . $this->runtime[$model->alias]['sphinx']->GetLastWarning());
  86.             }
  87.         }
  88.  
  89.         unset($query['conditions']);
  90.         unset($query['order']);
  91.         unset($query['offset']);
  92.         $query['page'] = 1;
  93.         if ($model->findQueryType == 'count')
  94.         {
  95.             $result['total'] = !empty($result['total']) ? $result['total'] :  0;
  96.             $query['fields'] = 'ABS(' . $result['total'] . ') AS count';
  97.  
  98.         }
  99.         else
  100.         {
  101.             if (isset($result['matches']))
  102.                 $ids = array_keys($result['matches']);
  103.             else
  104.                 $ids = array( 0);
  105.             $query['conditions'] = array($model->alias . '.'.$model->primaryKey => $ids);
  106.             $query['order'] = 'FIND_IN_SET('.$model->alias.'.'.$model->primaryKey.', \'' . implode(',', $ids) . '\')';
  107.  
  108.         }
  109.  
  110.         return $query;
  111.     }
  112. }
  113. ?>
  114.  


Как пользоваться:
В коде модели добавляем
<?php
    
var $actsAs = array('Sphinx');
?>


В контроллере используем:
<?php
$sphinx 
= array('matchMode' => SPH_MATCH_ALL'sortMode' => array(SPH_SORT_EXTENDED => '@relevance DESC'));
$results $this->Film->find('all', array('search' => 'что ищем''sphinx' => $sphinx));
?>

УПД: переформатировал код, т.к. хабр съел часть
Tags:
Hubs:
+18
Comments 8
Comments Comments 8

Articles