531 lines
18 KiB
PHP
531 lines
18 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Hura8\System\Model;
|
||
|
|
|
||
|
|
use Hura8\Interfaces\AppResponse;
|
||
|
|
use Hura8\System\Language;
|
||
|
|
use Hura8\Database\iConnectDB;
|
||
|
|
use Hura8\Interfaces\iSearch;
|
||
|
|
use Hura8\Traits\ClassCacheTrait;
|
||
|
|
|
||
|
|
abstract class aSearchBaseModel implements iSearch
|
||
|
|
{
|
||
|
|
|
||
|
|
use ClassCacheTrait;
|
||
|
|
|
||
|
|
/* @var iConnectDB $db */
|
||
|
|
protected $db;
|
||
|
|
|
||
|
|
protected $tb_main = "";
|
||
|
|
protected $tb_fulltext = "";
|
||
|
|
|
||
|
|
// if false then search 'nhà tôi' = 'nha toi', if true then 'nhà tôi' != 'nha toi'
|
||
|
|
// require rebuilding search if change this value
|
||
|
|
protected $search_vietnamese = false;
|
||
|
|
|
||
|
|
// require rebuilding search if change this value
|
||
|
|
protected $star_search = true; //values: 1|0, enable star search on fulltext: abc* -> matches: abcd, abc, abcde
|
||
|
|
|
||
|
|
// require rebuilding search if change this value
|
||
|
|
protected $min_star_search_length = 2; //min star word length: result: abcd -> keywords: ab, abc, abcd NOT a
|
||
|
|
|
||
|
|
// define list of fields to be the filters
|
||
|
|
protected $config_filter_fields = [
|
||
|
|
//format: field_name => map table_name.field
|
||
|
|
//'price' => "tb_product.price",
|
||
|
|
//'quantity' => "tb_product.quantity",
|
||
|
|
];
|
||
|
|
|
||
|
|
protected $config_fulltext_fields = [
|
||
|
|
//format: field_name => map [table_name.field]
|
||
|
|
//"product_keywords" => ["tb_product.title", "tb_product.model", "tb_product.sku"],
|
||
|
|
//"category_keywords" => ["tb_category.title"],
|
||
|
|
];
|
||
|
|
|
||
|
|
|
||
|
|
public function __construct(
|
||
|
|
$tb_main,
|
||
|
|
array $config_fulltext_fields ,
|
||
|
|
array $config_filter_fields = []
|
||
|
|
) {
|
||
|
|
|
||
|
|
// ovewrite default
|
||
|
|
if(defined('CONFIG_STAR_SEARCH')) $this->star_search = CONFIG_STAR_SEARCH;
|
||
|
|
if(defined('CONFIG_STAR_SEARCH_MIN_LENGTH')) $this->min_star_search_length = CONFIG_STAR_SEARCH_MIN_LENGTH;
|
||
|
|
if(defined('CONFIG_SEARCH_VIETNAMESE')) $this->search_vietnamese = CONFIG_SEARCH_VIETNAMESE;
|
||
|
|
|
||
|
|
$this->db = get_db('', ENABLE_DB_DEBUG);
|
||
|
|
$this->config_fulltext_fields = $config_fulltext_fields;
|
||
|
|
$this->config_filter_fields = $config_filter_fields;
|
||
|
|
|
||
|
|
$this->tb_main = $tb_main;
|
||
|
|
$part_name = str_replace("tb_", "", preg_replace("/[^a-z0-9_]/i", "", $tb_main));
|
||
|
|
$this->tb_fulltext = "tb_search_".strtolower($part_name);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @description get filter fields
|
||
|
|
* @param array[string]
|
||
|
|
*/
|
||
|
|
public function getFilterFields(): array {
|
||
|
|
return $this->config_filter_fields;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @description get fulltext fields
|
||
|
|
* @param array[string]
|
||
|
|
*/
|
||
|
|
public function getFulltextFields(): array {
|
||
|
|
return $this->config_fulltext_fields;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
public function getSampleData() : array {
|
||
|
|
$query = $this->db->runQuery(
|
||
|
|
"SELECT * FROM `".$this->tb_fulltext."` ORDER BY `item_id` DESC LIMIT 10"
|
||
|
|
);
|
||
|
|
|
||
|
|
return $this->db->fetchAll($query);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
public function getTableName() : string {
|
||
|
|
return $this->tb_fulltext;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param array $field_filters ["price" => [">", 100], "brand" => ["=", 1]]
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
protected function _buildFieldFilters(array $field_filters = []) {
|
||
|
|
$permit_operations = [">","=","<",">=","<=", "BETWEEN", "IN"];
|
||
|
|
$where_clause = [];
|
||
|
|
$bind_types = [];
|
||
|
|
$bind_values = [];
|
||
|
|
|
||
|
|
foreach ($field_filters as $field => $info) {
|
||
|
|
list($operation, $value) = $info;
|
||
|
|
|
||
|
|
$operation = strtoupper($operation);
|
||
|
|
|
||
|
|
if(!in_array(strtolower($operation), $permit_operations)) continue;
|
||
|
|
|
||
|
|
if($operation == 'BETWEEN') {
|
||
|
|
// $value must be array(value_int_1, value_int_2)
|
||
|
|
if(is_array($value) && sizeof($value) == 2) {
|
||
|
|
list($value_1, $value_2) = $value;
|
||
|
|
|
||
|
|
if(is_int($value_1) && is_int($value_2) && $value_1 < $value_2) {
|
||
|
|
$where_clause[] = " AND `".$field."` BETWEEN (?, ?) ";
|
||
|
|
|
||
|
|
$bind_types[] = "d";
|
||
|
|
$bind_types[] = "d";
|
||
|
|
|
||
|
|
$bind_values[] = $value_1;
|
||
|
|
$bind_values[] = $value_2;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if($operation == 'IN') {
|
||
|
|
// $value must be array(value1, value2)
|
||
|
|
if(is_array($value) && sizeof($value) > 0) {
|
||
|
|
$parameterized = [];
|
||
|
|
foreach ($value as $_v) {
|
||
|
|
$parameterized[] = "?";
|
||
|
|
$bind_types[] = "s";
|
||
|
|
$bind_values[] = $_v;
|
||
|
|
}
|
||
|
|
|
||
|
|
$where_clause[] = " AND `".$field."` IN (".join(",", $parameterized).") ";
|
||
|
|
}
|
||
|
|
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// default operation, comparison requires value to be a digit
|
||
|
|
$where_clause[] = " AND `".$field."` ".$operation." ? ";
|
||
|
|
$bind_types[] = "d";
|
||
|
|
$bind_values[] = $value;
|
||
|
|
}
|
||
|
|
|
||
|
|
return array(join(" ", $where_clause), $bind_types, $bind_values);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param $keyword
|
||
|
|
* @param array $field_filters ["price" => [">", 100], "brand" => ["=", 1]]
|
||
|
|
* @param array $fulltext_fields ['title_keywords', "category_keywords"]
|
||
|
|
* @param int $limit_result
|
||
|
|
* @return int[]
|
||
|
|
*/
|
||
|
|
public function find($keyword, array $field_filters = [], array $fulltext_fields = [], $limit_result = 2000) : array
|
||
|
|
{
|
||
|
|
|
||
|
|
if(!sizeof($fulltext_fields)) $fulltext_fields = array_keys($this->config_fulltext_fields);
|
||
|
|
|
||
|
|
$cache_key = md5("find-".$keyword);
|
||
|
|
|
||
|
|
return static::getCache($cache_key, function () use ($keyword, $field_filters, $fulltext_fields, $limit_result){
|
||
|
|
|
||
|
|
$keyword_clean = ($this->search_vietnamese) ? $this->make_text_search_vn($keyword) : $this->make_text_clean($keyword) ; //make_text_search_vn
|
||
|
|
|
||
|
|
$keyword_clean_ele = array_filter(explode(" ", $keyword_clean));
|
||
|
|
$build_boolean_search = "+".join(" +", $keyword_clean_ele);
|
||
|
|
|
||
|
|
if(!$limit_result || $limit_result > 5000) $limit_result = 5000;
|
||
|
|
$limit_condition = ($limit_result > 0) ? " LIMIT ".$limit_result : "";
|
||
|
|
|
||
|
|
list($where_clause, $bind_types, $bind_values) = $this->_buildFieldFilters($field_filters);
|
||
|
|
|
||
|
|
//validate search fields
|
||
|
|
$validated_fulltext_fields = array_filter($fulltext_fields, function ($item) { return array_key_exists($item, $this->config_fulltext_fields); });
|
||
|
|
|
||
|
|
if(!sizeof($validated_fulltext_fields)) {
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
|
||
|
|
$query = $this->db->runQuery(
|
||
|
|
"SELECT `item_id` FROM `".$this->tb_fulltext."`
|
||
|
|
WHERE MATCH(".join(',', $validated_fulltext_fields).") AGAINST('".$build_boolean_search."' IN BOOLEAN MODE)
|
||
|
|
".$where_clause."
|
||
|
|
ORDER BY `item_id` DESC
|
||
|
|
".$limit_condition."
|
||
|
|
",
|
||
|
|
$bind_types, $bind_values
|
||
|
|
);
|
||
|
|
|
||
|
|
return array_map(function ($item){ return $item['item_id']; }, $this->db->fetchAll($query) );
|
||
|
|
|
||
|
|
});
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
protected function getItemInfo($item_id)
|
||
|
|
{
|
||
|
|
$query = $this->db->runQuery(
|
||
|
|
"SELECT * FROM `".$this->tb_fulltext."` WHERE `item_id` = ? LIMIT 1",
|
||
|
|
['d'], [$item_id]
|
||
|
|
);
|
||
|
|
|
||
|
|
return $this->db->fetchAssoc($query);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
protected function checkExist($item_id) : bool
|
||
|
|
{
|
||
|
|
$query = $this->db->runQuery(
|
||
|
|
"SELECT `item_id` FROM `".$this->tb_fulltext."` WHERE `item_id` = ? LIMIT 1",
|
||
|
|
['d'], [$item_id]
|
||
|
|
);
|
||
|
|
|
||
|
|
return (bool) $this->db->fetchAssoc($query);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// get all table_fields to watch which will affect the search
|
||
|
|
protected function getWatchTableFields() {
|
||
|
|
$result = [];
|
||
|
|
foreach ($this->config_filter_fields as $field => $table_field ) {
|
||
|
|
$result[] = $table_field;
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach ($this->config_fulltext_fields as $field => $table_fields ) {
|
||
|
|
$result = array_merge($result, $table_fields);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $result;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @description update or create item if not exist
|
||
|
|
* @param $item_id
|
||
|
|
* @param array $table_field_values
|
||
|
|
$table_field_values = [
|
||
|
|
"tb_product.price" => 2000000,
|
||
|
|
"tb_product.title" => "Máy tính ABC",
|
||
|
|
"tb_category.price" => "Máy tính",
|
||
|
|
|
||
|
|
"tb_product.field_not_be_update" => "Mmodel",
|
||
|
|
];
|
||
|
|
* @return AppResponse
|
||
|
|
*/
|
||
|
|
public function updateItem($item_id, array $table_field_values = []) : AppResponse
|
||
|
|
{
|
||
|
|
|
||
|
|
$fulltext_fields = [];
|
||
|
|
foreach ($this->config_fulltext_fields as $fulltext_field => $fulltext_map_fields ) {
|
||
|
|
foreach ($fulltext_map_fields as $_table_field) {
|
||
|
|
if(array_key_exists($_table_field, $table_field_values)) {
|
||
|
|
$fulltext_fields[$fulltext_field][$_table_field] = $table_field_values[$_table_field];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//echo "fulltext_fields";
|
||
|
|
//debug_var($fulltext_fields);
|
||
|
|
//echo "<br />";
|
||
|
|
|
||
|
|
$field_filters = [];
|
||
|
|
foreach ($this->config_filter_fields as $filter_field => $filter_map_field ) {
|
||
|
|
if(array_key_exists($filter_map_field, $table_field_values)) {
|
||
|
|
$field_filters[$filter_field] = $table_field_values[$filter_map_field];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//echo "field_filters";
|
||
|
|
//debug_var($field_filters);
|
||
|
|
|
||
|
|
// nothing to update
|
||
|
|
if(!sizeof($fulltext_fields) && !sizeof($field_filters)) {
|
||
|
|
return new AppResponse('error', "nothing to update" );
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// create entry if not exist
|
||
|
|
if(!$this->checkExist($item_id)) {
|
||
|
|
$this->db->insert($this->tb_fulltext, ['item_id' => $item_id, 'create_time' => CURRENT_TIME]);
|
||
|
|
}
|
||
|
|
|
||
|
|
$current_info = $this->getItemInfo($item_id);
|
||
|
|
if(!$current_info) {
|
||
|
|
return new AppResponse('error', "Cannot find record for ".$item_id );
|
||
|
|
}
|
||
|
|
|
||
|
|
// update
|
||
|
|
$updated_fulltext = [];
|
||
|
|
|
||
|
|
foreach ($this->config_fulltext_fields as $_filter_field => $_n ) {
|
||
|
|
if(!isset($fulltext_fields[$_filter_field])) continue;
|
||
|
|
|
||
|
|
$current_filter_field_base = ($current_info[$_filter_field."_base"]) ? \json_decode($current_info[$_filter_field."_base"], true) : [];
|
||
|
|
|
||
|
|
$new_filter_field_base = $current_filter_field_base;
|
||
|
|
|
||
|
|
foreach ($fulltext_fields[$_filter_field] as $_table_field => $_new_value) {
|
||
|
|
$new_filter_field_base[$_table_field] = $_new_value;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(json_encode($new_filter_field_base) != json_encode($current_filter_field_base)) {
|
||
|
|
$updated_fulltext[$_filter_field."_base"] = $new_filter_field_base;
|
||
|
|
$updated_fulltext[$_filter_field] = ($this->search_vietnamese) ? $this->make_text_search_vn(join(" ", array_values($new_filter_field_base))) : $this->make_text_clean(join(" ", array_values($new_filter_field_base)));
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
$updated_filters = [];
|
||
|
|
foreach ($this->config_filter_fields as $_filter_field => $_table_field ) {
|
||
|
|
if(!isset($field_filters[$_filter_field])) continue;
|
||
|
|
|
||
|
|
if($field_filters[$_filter_field] != $current_info[$_filter_field] ) {
|
||
|
|
$updated_filters[$_filter_field] = $field_filters[$_filter_field];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// nothing to update
|
||
|
|
if(!sizeof($updated_filters) && !sizeof($updated_fulltext)) {
|
||
|
|
return new AppResponse('error', "nothing to update" );
|
||
|
|
}
|
||
|
|
|
||
|
|
$updated_info = array_merge($updated_filters, $updated_fulltext);
|
||
|
|
$updated_info['last_update'] = CURRENT_TIME;
|
||
|
|
|
||
|
|
//echo "updated_info = <br /> ";
|
||
|
|
//debug_var($updated_info);
|
||
|
|
|
||
|
|
$this->db->update(
|
||
|
|
$this->tb_fulltext,
|
||
|
|
$updated_info,
|
||
|
|
['item_id' => $item_id]
|
||
|
|
);
|
||
|
|
|
||
|
|
return new AppResponse('ok');
|
||
|
|
}
|
||
|
|
|
||
|
|
public function deleteItem($item_id) : AppResponse
|
||
|
|
{
|
||
|
|
$this->db->runQuery(
|
||
|
|
"DELETE FROM `".$this->tb_fulltext."` WHERE `item_id` = ? LIMIT 1",
|
||
|
|
['d'], [$item_id]
|
||
|
|
);
|
||
|
|
|
||
|
|
return new AppResponse('ok');
|
||
|
|
}
|
||
|
|
|
||
|
|
public function deleteItems(array $item_list_ids) : AppResponse
|
||
|
|
{
|
||
|
|
list($parameterized_ids, $bind_types) = create_bind_sql_parameter_from_value_list($item_list_ids, "int");
|
||
|
|
|
||
|
|
$this->db->runQuery(
|
||
|
|
"DELETE FROM `".$this->tb_fulltext."` WHERE `item_id` IN (".$parameterized_ids.") ",
|
||
|
|
$bind_types,
|
||
|
|
$item_list_ids
|
||
|
|
);
|
||
|
|
|
||
|
|
return new AppResponse('ok');
|
||
|
|
}
|
||
|
|
|
||
|
|
public function recreateTableSearch() {
|
||
|
|
if($this->db->checkTableExist($this->tb_fulltext)) {
|
||
|
|
$this->db->runQuery(
|
||
|
|
"DROP TABLE `".$this->tb_fulltext."` "
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->createTableSearch();
|
||
|
|
}
|
||
|
|
|
||
|
|
public function createTableSearch() {
|
||
|
|
// check if table exist
|
||
|
|
if($this->db->checkTableExist($this->tb_fulltext)) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(!$this->db->checkTableExist($this->tb_main)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
$sql = "CREATE TABLE `".$this->tb_fulltext."` ( `item_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', ";
|
||
|
|
|
||
|
|
// add fields
|
||
|
|
|
||
|
|
foreach ($this->config_filter_fields as $_filter_field => $_map_table_field ) {
|
||
|
|
list($_table, $_f) = explode(".", $_map_table_field);
|
||
|
|
|
||
|
|
$_table_info = $this->db->getTableInfo($_table);
|
||
|
|
|
||
|
|
$column_default = $_table_info[$_f]['COLUMN_DEFAULT'];
|
||
|
|
|
||
|
|
$default_value = (in_array($_table_info[$_f]['DATA_TYPE'], ['mediumint', 'int', 'tinyint', 'double', 'float'])) ? 0 : $column_default;
|
||
|
|
|
||
|
|
$sql .= " `".$_filter_field."` ".$_table_info[$_f]['COLUMN_TYPE']." NOT NULL DEFAULT '".$default_value."', ";
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach ($this->config_fulltext_fields as $_filter_field => $_t ) {
|
||
|
|
$sql .= " `".$_filter_field."` TEXT NULL , ";
|
||
|
|
|
||
|
|
// create field-data to compare new values before re-indexing
|
||
|
|
$sql .= " `".$_filter_field."_base` TEXT NULL , ";
|
||
|
|
}
|
||
|
|
|
||
|
|
$sql .= " `create_time` int(11) NOT NULL DEFAULT '0', ";
|
||
|
|
$sql .= " `last_update` int(11) NOT NULL DEFAULT '0', ";
|
||
|
|
|
||
|
|
// index
|
||
|
|
|
||
|
|
foreach ($this->config_filter_fields as $_filter_field => $_data_type ) {
|
||
|
|
$sql .= " INDEX (`".$_filter_field."`), ";
|
||
|
|
}
|
||
|
|
|
||
|
|
// fulltext on separate columns
|
||
|
|
foreach ($this->config_fulltext_fields as $_filter_field => $_t ) {
|
||
|
|
$sql .= " FULLTEXT INDEX (`".$_filter_field."` ) , ";
|
||
|
|
}
|
||
|
|
|
||
|
|
// create full text for all columns combined, so we can do query match(col_1, col_2) against keyword
|
||
|
|
$_filter_fields = array_keys($this->config_fulltext_fields);
|
||
|
|
if(sizeof($_filter_fields)) $sql .= " FULLTEXT INDEX (".join(", ", $_filter_fields).") , ";
|
||
|
|
|
||
|
|
$sql .= " PRIMARY KEY ( `item_id` ) ";
|
||
|
|
$sql .= " ) ENGINE=InnoDB DEFAULT CHARSET=utf8";
|
||
|
|
|
||
|
|
//return $sql;
|
||
|
|
$this->db->runQuery($sql);
|
||
|
|
|
||
|
|
// add foreign key constraint
|
||
|
|
$this->db->runQuery("
|
||
|
|
ALTER TABLE `".$this->tb_fulltext."` ADD FOREIGN KEY (`item_id`) REFERENCES `".$this->tb_main."`(`id`) ON DELETE CASCADE;
|
||
|
|
");
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//11-11-2012 chuyen text thanh tieng viet voi dau chuyen doi: vd. nhà = nhas
|
||
|
|
//because mysql allow fulltext search with minimum 4 characters, we have a trick: add hura to everyone what has length < 4
|
||
|
|
protected function make_text_search_vn($text, $enable_star = false){
|
||
|
|
$text = Language::convertText($text);
|
||
|
|
$text = preg_replace("@[^a-z0-9\s]@si", " ", strtolower($text));
|
||
|
|
//$text = str_replace(" "," ",$text);
|
||
|
|
$text_ele = array_filter(explode(" ", $text));
|
||
|
|
$new_text = "";
|
||
|
|
foreach($text_ele as $ele) {
|
||
|
|
if($ele == '/' ) continue; //skip this character if it stands alone
|
||
|
|
|
||
|
|
if(strlen($ele) < 4 || $ele == 'plus') $new_text .= " hura".$ele;
|
||
|
|
else $new_text .= " ".$ele;
|
||
|
|
}
|
||
|
|
return trim($new_text);
|
||
|
|
}
|
||
|
|
|
||
|
|
//11-11-2012 chuyen text thanh tieng viet khong dau: vd. nhà = nha
|
||
|
|
/*
|
||
|
|
@variable:
|
||
|
|
- $text: text to be index
|
||
|
|
|
||
|
|
//16-11-2012
|
||
|
|
- $enable_star:
|
||
|
|
true: allow search abcd by word: ab or abc
|
||
|
|
false: not enabled
|
||
|
|
- $min_len: if $enable_star = true, abcd -> tao thanh: ab, abd, abcd (if $min_len = 2)
|
||
|
|
*/
|
||
|
|
protected function make_text_clean($_text, $enable_star = false){
|
||
|
|
//$text = Language::chuyenKhongdau(Language::convert_lower($text));
|
||
|
|
$text = Language::chuyenKhongdau($_text);
|
||
|
|
|
||
|
|
$text = preg_replace("@[^a-z0-9\s]@si", " ", strtolower($text));
|
||
|
|
|
||
|
|
$text_ele = array_filter(explode(" ", $text));
|
||
|
|
$new_text = "";
|
||
|
|
foreach($text_ele as $ele) {
|
||
|
|
|
||
|
|
if($this->star_search && $enable_star) {
|
||
|
|
|
||
|
|
$word_list = static::create_star_search($ele, $this->min_star_search_length);
|
||
|
|
foreach($word_list as $new_ele) {
|
||
|
|
if(strlen($new_ele) < 4 || $ele == 'plus') $new_text .= " hura".$new_ele;
|
||
|
|
else $new_text .= " ".$new_ele;
|
||
|
|
}
|
||
|
|
|
||
|
|
}else{
|
||
|
|
if(strlen($ele) < 4 || $ele == 'plus') $new_text .= " hura".$ele;
|
||
|
|
else $new_text .= " ".$ele;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return trim($new_text);
|
||
|
|
}
|
||
|
|
|
||
|
|
//16-11-2012
|
||
|
|
//create all possible combination for a word for star search: abcd -> tao thanh: ab, abd, abcd, bc, bcd, cd (if $min_len = 2)
|
||
|
|
protected function create_star_search($word, $min_len = 2){
|
||
|
|
if($min_len < 2) $min_len = 2; //in case missing value for CONFIG_STAR_SEARCH_MIN_LENGTH
|
||
|
|
$word_len = strlen($word);
|
||
|
|
$result = array();
|
||
|
|
if($word_len <= $min_len) return array($word);
|
||
|
|
for($i = $min_len; $i < $word_len; $i ++ ){
|
||
|
|
$result[] = substr($word, 0, $i);
|
||
|
|
}
|
||
|
|
$result[] = $word;
|
||
|
|
|
||
|
|
//09-01-2012
|
||
|
|
//reduce $word 1 character to create new word and create combination from there
|
||
|
|
$new_word = substr($word, 1);
|
||
|
|
$new_result = self::create_star_search($new_word, $min_len = 2);
|
||
|
|
foreach($new_result as $el){
|
||
|
|
$result[] = $el;
|
||
|
|
}
|
||
|
|
|
||
|
|
return array_unique($result);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|