View source
<?php
namespace Drupal\suggestion;
class SuggestionHelper {
const C = 8;
const MAX = 100;
const MAX_LEVEL = 4;
const MIN = 2;
const EXP = 0.5;
public static function alterElement(array &$form, $field_name, $level = 1) {
$suxs = FALSE;
$types = [
'search',
'textfield',
];
if ($level > self::MAX_LEVEL) {
return FALSE;
}
foreach ($form as $key => &$element) {
if ($key == $field_name && !empty($form[$key]['#type']) && in_array($form[$key]['#type'], $types)) {
$form[$key]['#autocomplete_route_name'] = 'suggestion.autocomplete';
$suxs = TRUE;
}
elseif (is_array($element)) {
$suxs = self::alterElement($element, $field_name, $level + 1);
}
if ($suxs) {
break;
}
}
if ($suxs && $level == 1) {
$form['#submit'][] = 'suggestion_surfer_submit';
}
return $suxs;
}
public static function atomize($txt = '') {
$atoms = [];
$stopwords = self::getStops('stopwords');
foreach (preg_split('/\\s+/', $txt) as $atom) {
if (!empty($stopwords[$atom])) {
continue;
}
$atoms[$atom] = $atom;
}
return $atoms;
}
public static function calculateDensity($src = 0, $atoms = 1, $qty = 0) {
$score = intval($src) * self::C;
return (double) $score + self::getDelta(self::MAX - $score, intval(pow($atoms + $qty, self::EXP)));
}
public static function getConfig($key = '') {
$cfg =& drupal_static(__CLASS__ . '_' . __FUNCTION__, \Drupal::configFactory()
->get('suggestion.config'));
return $key ? $cfg
->get($key) : (object) $cfg
->get();
}
public static function getStops($key = '') {
$cfg =& drupal_static(__CLASS__ . '_' . __FUNCTION__, \Drupal::configFactory()
->get('suggestion.stopword'));
return $key ? $cfg
->get($key) : (object) $cfg
->get();
}
public static function index($last_nid = 0, $limit = NULL) {
$count =& drupal_static(__CLASS__ . '_' . __FUNCTION__ . '_count', 0);
$nid =& drupal_static(__CLASS__ . '_' . __FUNCTION__ . '_nid', 0);
self::setConfig('synced', TRUE);
if (!$last_nid) {
SuggestionStorage::deleteContentSuggestion();
SuggestionStorage::updateContentSrc();
}
$titles = SuggestionStorage::getTitles($last_nid, $limit);
foreach ($titles as $nid => $title) {
$count += self::insert($title, SuggestionStorage::CONTENT_BIT);
}
}
public static function insert($txt = '', $src = SuggestionStorage::CONTENT_BIT, $qty = NULL) {
$count = 0;
$max = self::getConfig('max');
$txt = self::tokenize($txt, self::getConfig('min'));
if (!$txt) {
return 0;
}
$atoms = self::atomize($txt);
foreach (array_keys(self::ngrams($atoms)) as $ngram) {
if (strlen($ngram) > $max) {
continue;
}
$count = str_word_count($ngram);
$qty = is_numeric($qty) ? $qty + 1 : SuggestionStorage::getNgramQty($ngram) + 1;
$src = SuggestionStorage::getBitmap($ngram, $src);
$key = [
'ngram' => $ngram,
];
$fields = [
'atoms' => $count,
'density' => self::calculateDensity($src, $count, $qty),
'qty' => $qty,
'src' => $src,
];
SuggestionStorage::mergeSuggestion($key, $fields);
$count++;
}
return $count;
}
public static function ngrams(array $atoms = []) {
$max = self::getConfig('atoms_max');
$min = self::getConfig('atoms_min');
$ngrams = [];
$count = count($atoms) - $min;
for ($i = 0; $i <= $count; $i++) {
for ($j = $min; $j <= $max; $j++) {
$ngrams[implode(' ', array_slice($atoms, $i, $j))] = 1;
}
}
$atoms = array_reverse($atoms);
for ($i = 0; $i <= $count; $i++) {
for ($j = $min; $j <= $max; $j++) {
$ngrams[implode(' ', array_slice($atoms, $i, $j))] = 1;
}
}
return $ngrams;
}
public static function setConfig($key = '', $val = NULL) {
$cfg =& drupal_static(__CLASS__ . '_' . __FUNCTION__, \Drupal::configFactory()
->getEditable('suggestion.config'));
return $key ? $cfg
->set($key, $val)
->save() : NULL;
}
public static function setStops($key = '', $val = NULL) {
$cfg =& drupal_static(__CLASS__ . '_' . __FUNCTION__, \Drupal::configFactory()
->getEditable('suggestion.stopword'));
return $key ? $cfg
->set($key, $val)
->save() : NULL;
}
public static function srcBits($src = 0) {
$bits = [];
if (intval($src) <= 0) {
return [
0,
];
}
foreach (array_keys(SuggestionStorage::getSrcOptions()) as $bit) {
if ($bit & $src) {
$bits[] = $bit;
}
}
return $bits;
}
public static function optionBits(array $bits = []) {
$src = 0;
foreach ($bits as $bit) {
$src |= intval($bit);
}
return $src;
}
public static function tokenize($txt = '', $min = 4) {
$min--;
$regx = [
'/[^a-z]+/s' => ' ',
'/\\b(\\w{1,' . $min . '})\\b/s' => '',
'/\\s\\s+/s' => ' ',
'/^\\s+|\\s+$/s' => '',
];
return preg_replace(array_keys($regx), array_values($regx), strtolower(trim($txt)));
}
public static function types() {
$types =& drupal_static(__CLASS__ . '_' . __FUNCTION__, NULL);
if (is_array($types)) {
return $types;
}
foreach (self::getConfig('types') as $type => $status) {
if ($status) {
$types[] = $type;
}
}
return $types ? $types : [];
}
public static function updateSrc($ngram = '', $src = 0) {
$obj = SuggestionStorage::getSuggestion($ngram);
$key = [
'ngram' => $ngram,
];
$fields = [
'atoms' => $obj->atoms,
'density' => self::calculateDensity($src, $obj->atoms, $obj->qty),
'qty' => $obj->qty,
'src' => $src,
];
return SuggestionStorage::mergeSuggestion($key, $fields);
}
protected static function getDelta($delta, $n) {
if ($delta < self::MIN || !$n) {
return 0;
}
$x = pow($delta, self::EXP);
return $x + self::getDelta($delta - $x, $n - 1);
}
}