get(); $map = []; foreach ($features as $feature){ $map[$feature->id] = ["type"=>$feature->type,"logic"=>$feature->logic,"describe"=>$feature->describe]; } return $map; } public function translationFeature($str) { if (!$str)return null; $result = []; preg_match_all('/\d+|[\&\|\(\)]/',$str,$result); //初次匹配以数字&|()为分隔符生成数组 $sign = 0; //为第二次切割做起点标记 $model = [];//第二次切割数组 $ids = [];//记录出现的特征ID,统一查询 foreach ($result[0] as $index => &$str){ if (is_numeric($str)){ $model[] = array_slice($result[0],$sign,($index-$sign)+1); $sign = $index+1; $ids[] = $str; continue; } if ($index == count($result[0])-1 && $str == ')'){ $model[] = [")"]; } }//以数字为标准切割策略组 $features = Feature::query()->find($ids);//查询出现的特征 $featureMap = []; foreach ($features as $index => $feature){ $featureMap[$feature->id] = $index; }//为查询的特征重组为key-val形式数组留做引用 foreach ($model as $index => &$m){ $arr = [ "strategyGroupStartSign" => false,//是否为策略组起点,这将在解析时解析为 ( "calculation" => "",//运算规则,目前仅有 &,| 翻译后填入 "type"=>"", //特征类型 "id"=>"", //特征ID "logic"=>"", //特征逻辑 "describe"=>"", //特征信息 "strategyGroupEndSign" => false,//是否为策略组终点,这将在解析时解析为 ) ];//最终对象组模型,策略组将几组特征组合引用 foreach ($m as $str){ if (is_numeric($str)){//填入特征信息 if (isset($featureMap[$str])){ $arr["type"] = $features[$featureMap[$str]]->type; $arr["id"] = $features[$featureMap[$str]]->id; $arr["logic"] = $features[$featureMap[$str]]->logic; $arr["describe"] = $features[$featureMap[$str]]->describe; } continue; } switch ($str){//特殊字符的翻译 case "(": $arr["strategyGroupStartSign"] = true; break; case ")": $model[$index-1]["strategyGroupEndSign"] = true; break; case "&": $arr["calculation"] = "并且"; break; case "|": $arr["calculation"] = "或"; break; } } if (!$arr["id"]){ unset($model[$index]); continue; } $m = $arr;//变更当前指针为翻译结果 } return $model; } public function analysisFeature($features) { $str = ""; $map = []; foreach ($features as &$feature){ if (!$feature["type"] || !$feature["logic"] || !$feature["describe"])continue; $f = Feature::query()->firstOrCreate([ "type"=>$feature["type"], //特征类型 "logic"=>$feature["logic"], //特征逻辑 "describe"=>$feature["describe"], //特征信息 ]); $feature["id"] = $f->id; $map[$feature["id"]] = $f; if ($feature["calculation"] == '并且')$str .= '&'; else $str .= '|'; if ($feature["strategyGroupStartSign"])$str .= "("; $str .= $feature["id"]; if ($feature["strategyGroupEndSign"])$str .= ")"; } return ['feature'=>$str,"map"=>$map]; } public function formatFeature(array $features, $value, $columnMapping = null) { if (!$features)return $value; preg_match_all('/\d+|[\&\|\(\)]/',$value,$result); foreach ($result[0] as &$str){ if (is_numeric($str) && isset($features[$str])){ $column = $features[$str]["type"]; $logic = $features[$str]["logic"]; $describe = $features[$str]["describe"]; if ($columnMapping){ $column = $columnMapping[$column] ?? $column; switch ($logic){ case "包含": $logic = " like "; $describe = "%".$describe."%"; break; case "不包含": $logic = " not like "; $describe = "%".$describe."%"; break; case "等于": $logic = " = "; break; } $str = $column.$logic.$describe; }else $str = $features[$str]["type"].' '.$features[$str]["logic"].' '.$features[$str]["describe"]; } if ($str == "&"){ if ($columnMapping) $str = " and "; else $str = " 并且 "; } if ($str == "|"){ if ($columnMapping) $str = " or "; else $str = " 或 "; } } return implode("",$result[0]); } public function matchFeature($value, $columnMapping, $matchObject) :bool { preg_match_all('/\d+/',$value,$ids); if ($ids[0])$fs = Feature::query()->whereIn("id",$ids[0])->get(); else return false; $features = []; foreach ($fs as $f){ $features[$f->id] = $f; } preg_match_all('/\d+|[\&\|\(\)]/',$value,$result); foreach ($result[0] as &$str) { if (is_numeric($str) && isset($features[$str])) { $column = $features[$str]["type"]; $logic = $features[$str]["logic"]; $describe = $features[$str]["describe"]; $value = isset($columnMapping[$column]) ? $matchObject[$columnMapping[$column]] : ''; switch ($logic) { case "包含": $str = mb_strpos($value,$describe) === false ? 'false' : 'true'; break; case "不包含": $str = mb_strpos($value,$describe) === false ? 'true' : 'false'; break; case "等于": $str = $value == $describe ? 'true' : 'false'; break; } continue; } if ($str == "&") { $str = '&&'; continue; } if ($str == "|") { $str = '||'; } } $is = implode("",$result[0]); return eval("return $is;"); } }