Version: current

      1 <?php
      2
      3 /**
      4  * Класс для работы с PHPMorphy
      5  *
      6  * @author inxo
      7  */
      8 require_once 'phpmorphy/common.php';
      9
     10 class SSMorphy {
     11
     12
     13     static $min_word_len = 3;
     14     static $min_mysql_len = 3;
     15     static $force_base_form = false;
     16
     17     private $dir = false;
     18     private $ruMorphy;
     19     private $enMorphy;
     20
     21     function init() {
     22         if (!$this->dir) {
     23             $this->dir = dirname(__FILE__) . '/dicts';
     24             try {
     25                 $this->ruMorphy = new phpMorphy($this->dir, 'ru_RU');
     26             } catch (phpMorphy_Exception $e) {
     27                 die('Error occured while creating phpMorphy instance: ' . $e->getMessage());
     28             }
     29
     30             try {
     31                 $this->enMorphy = new phpMorphy($this->dir, 'en_EN');
     32             } catch (phpMorphy_Exception $e) {
     33                 die('Error occured while creating phpMorphy instance: ' . $e->getMessage());
     34             }
     35         }
     36     }
     37
     38     static function createSearchCriteria($keywords) {
     39         $dict = new SSMorphy();
     40         return $dict->getSearchCriteria($keywords);
     41     }
     42
     43     function getSearchCriteria($keywords) {
     44         $this->init();
     45
     46         $list = preg_split('/\s+/', trim($keywords));
     47         $list = array_unique($list);
     48         $f = create_function('&$v,$k,$w', '$v = (($v == $w) ? ">" : "<") . $v;');
     49
     50         // формируем запрос для match .. against: требуем все слова в любых словоформах, исходная форма слова имеет повышенный вес
     51         foreach ($list as $i => $keyword) {
     52             $upperKeyword = mb_strtoupper($keyword);
     53             $resultKeywords = array();
     54
     55             // !!! могут быть проблемы из-за ft_min_word_len в mysql - лучше пропускать все что меньше его
     56             // TODO по идее надо брать текущее значение с самого mysql
     57             if (mb_strlen($upperKeyword) < self::$min_mysql_len) continue;
     58
     59             if (preg_match('/^\d+$/u', $upperKeyword)) {
     60                 // числа - как есть
     61                 $resultKeywords[] = '>' . $upperKeyword;
     62             }
     63             else {
     64                 if (mb_strlen($upperKeyword) < self::$min_word_len) continue;
     65                 // RNW
     66                 // В многобайтовых кодировках количество символов НЕОБХОДИМО
     67                 // проверять через mb_strlen
     68                 // в противном случае будет выдавать числоСимволов*2
     69                 // и подобные проверки НЕ БУДУТ работать
     70                 if (mb_strlen($upperKeyword) < self::$min_word_len) continue;
     71                 // FIXME использовать список стоп-слов, которые всега выкидываем,
     72                 // например союзы, предлоги и пр. мусор: а, в, и, по, на, но, ...
     73
     74                 $base = (self::$force_base_form) ? $this->createBaseForm($upperKeyword) : $upperKeyword;
     75
     76                 if (is_array($ru = $this->ruMorphy->getAllForms($base))) {
     77                     // поднимем приоритет запрашиваемой формы слова
     78                     array_walk($ru, $f, $upperKeyword);
     79                     $resultKeywords = array_merge($resultKeywords, $ru);
     80                 }
     81
     82                 if (is_array($en = $this->enMorphy->getAllForms($base))) {
     83                     // поднимем приоритет запрашиваемой формы слова
     84                     array_walk($en, $f, $upperKeyword);
     85                     $resultKeywords = array_merge($resultKeywords, $en);
     86                 }
     87
     88                 // если нет словоформ - добавим само слово
     89                 if (empty($resultKeywords)) {
     90                     $resultKeywords[] = '>' . $upperKeyword;
     91                 }
     92             }
     93
     94             $list[$i] = '+('.implode(" ", $resultKeywords).')';
     95         }
     96
     97         // добавляем саму фразу целиком с повышенным весом, но как необязательную (страницы с точным совпадением будут выше)
     98         $query = '>"' . $keywords . '" ' . implode(' ', $list);
     99
    100         return $query;
    101     }
    102
    103     function createBaseForm($word) {
    104         $this->init();
    105         $upperKeyword = mb_strtoupper($word, 'UTF-8');
    106         $max = '';
    107         // Russian
    108         $ru = $this->ruMorphy->getBaseForm($upperKeyword);
    109         if ($ru && ($ru!='' || is_array($ru))) {
    110             foreach ($ru as $base) {
    111                 if (strlen($base) == strlen($upperKeyword))
    112                     return $base;
    113                 if (strlen($max) < strlen($base))
    114                     $max = $base;
    115             }
    116         }
    117         if (strlen($max) > 0)
    118             return $max;
    119
    120         // English
    121         $en = $this->enMorphy->getBaseForm($upperKeyword);
    122         if ($en && ($en!='' || is_array($en))) {
    123             $max = '';
    124             foreach ($en as $base) {
    125                 if (strlen($base) == strlen($upperKeyword))
    126                     return $base;
    127                 if (strlen($max) < strlen($base))
    128                     $max = $base;
    129             }
    130         }
    131         if (strlen($max) > 0)
    132             return $max;
    133
    134         return $upperKeyword;
    135     }
    136
    137 }
    138

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -