📄 expr.inc.php
字号:
return '';
}
$sql =
'SELECT ' . "\n";
if ($this->context == ExprContext::DOCUMENT)
{
// we are doing this because content table is dependant on metadata table
if ($this->used_tables['document_content_version'] > 0)
{
$this->used_tables['document_metadata_version']++;
}
$sql .=
' DISTINCT d.id, dmv.name as title';
}
else
{
$sql .=
' DISTINCT f.id, f.name as title';
}
$offset=0;
foreach($this->db as $expr)
{
$offset++;
$sql .= ", ifnull(" . $this->getSQLEvalExpr($expr) . ",0) as expr$offset ";
}
foreach($this->metadata as $expr)
{
$offset++;
$sql .= ", ifnull(" . $this->getSQLEvalExpr($expr) . ",0) as expr$offset ";
}
$sql .=
"\n" . 'FROM ' ."\n";
if ($this->context == ExprContext::DOCUMENT)
{
$primaryAlias = 'd';
$sql .= ' documents d ' ."\n";
if ($this->used_tables['document_metadata_version'] > 0)
{
$sql .= ' INNER JOIN document_metadata_version dmv ON d.metadata_version_id=dmv.id' . "\n";
}
if ($this->used_tables['document_content_version'] > 0)
{
$sql .= ' INNER JOIN document_content_version dcv ON dmv.content_version_id=dcv.id ' . "\n";
}
if ($this->used_tables['document_fields_link'] > 0)
{
$sql .= ' LEFT JOIN document_fields_link pdfl ON dmv.id=pdfl.metadata_version_id ' . "\n";
}
if ($this->used_tables['tag_words'] > 0)
{
$sql .= ' LEFT OUTER JOIN document_tags dt ON dt.document_id=d.id ' . "\n" .
' LEFT OUTER JOIN tag_words tw ON dt.tag_id = tw.id ' . "\n";
}
}
else
{
$primaryAlias = 'f';
$sql .= ' folders f ' ."\n";
}
$offset = 0;
foreach($this->db as $expr)
{
$field = $expr->left();
$jointable=$field->getJoinTable();
if (!is_null($jointable))
{
$fieldname = $this->resolveTableToAlias($field->getTable()) . '.' . $field->getField();
$joinalias = "$jointable$offset";
$joinfield = $field->getJoinField();
$sql .= " LEFT OUTER JOIN $jointable $joinalias ON $fieldname=$joinalias.$joinfield\n";
}
$offset++;
}
if ($this->context == ExprContext::DOCUMENT)
{
$offset=0;
foreach($this->metadata as $expr)
{
$offset++;
$field = $expr->left();
$fieldid = $field->getFieldId();
$sql .= " LEFT JOIN document_fields_link dfl$offset ON dfl$offset.metadata_version_id=d.metadata_version_id AND dfl$offset.document_field_id=$fieldid" . "\n";
$sql .= " LEFT JOIN document_fields df$offset ON df$offset.id=dfl$offset.document_field_id" . "\n";
}
}
// Add permissions sql for read access
$oPermission =& KTPermission::getByName('ktcore.permissions.read');
$permId = $oPermission->getID();
$oUser = User::get($_SESSION['userID']);
$aPermissionDescriptors = KTPermissionUtil::getPermissionDescriptorsForUser($oUser);
$sPermissionDescriptors = empty($aPermissionDescriptors)? -1: implode(',', $aPermissionDescriptors);
$sql .= "INNER JOIN permission_lookups AS PL ON $primaryAlias.permission_lookup_id = PL.id\n";
$sql .= 'INNER JOIN permission_lookup_assignments AS PLA ON PL.id = PLA.permission_lookup_id AND PLA.permission_id = '.$permId. " \n";
$sql .= "WHERE PLA.permission_descriptor_id IN ($sPermissionDescriptors) AND ";
if ($this->context == ExprContext::DOCUMENT)
{
$sql .= "dmv.status_id=1 AND d.status_id=1 AND d.linked_document_id is null";
}
else
{
$sql .= "f.linked_folder_id is null";
}
$sql .= ' AND ';
return $sql;
}
private function resolveMetadataOffset($expr)
{
if (!$expr->left()->isMetadataField())
{
throw new Exception(_kt('Metadata field expected'));
}
$offset=0;
foreach($this->metadata as $item)
{
if ($item->getExprId() == $expr->getExprId())
{
return $offset;
}
$offset++;
}
throw new Exception('metadata field not found');
}
private function resolveJoinOffset($expr)
{
$offset=0;
foreach($this->db as $item)
{
if ($item->getExprId() == $expr->getExprId())
{
return $offset;
}
$offset++;
}
throw new Exception('join field not found');
}
private function buildCoreSQLExpr($expr)
{
$left = $expr->left();
$right = $expr->right();
if (DefaultOpCollection::isBoolean($expr))
{
$query = '(' . $this->buildCoreSQLExpr($left) . ' ' . $expr->op() . ' ' . $this->buildCoreSQLExpr($right) . ')';
}
else
{
if (($this->context & $expr->appliesToContext()) == $this->context)
{
$query = $this->getSQLEvalExpr($expr);
}
else
{
$query = 'false';
}
}
return $query;
}
public function buildComplexQuery($expr)
{
// print "building complex \n\n";
$this->exploreExprs($expr);
$sql = $this->buildCoreSQL();
if (empty($sql))
{
return '';
}
$expr = $this->buildCoreSQLExpr($expr);
$sql .= $expr;
$config = KTConfig::getSingleton();
$maxSqlResults = $config->get('search/maxSqlResults', 1000);
$sql .= "limit $maxSqlResults";
return $sql;
}
public function buildSimpleQuery($op, $group)
{
// print "building simple \n\n";
$this->exploreGroup($group);
$sql = $this->buildCoreSQL();
$offset=0;
foreach($this->db as $expr)
{
if ($offset++)
{
$sql .= " $op\n " ;
}
$field = $expr->left();
if (is_null($field->getJoinTable()))
{
$alias = $this->resolveTableToAlias($field->getTable());
$fieldname = $alias . '.' . $field->getField();
}
else
{
$offset = $this->resolveJoinOffset($expr);
$matching = $field->getMatchingField();
$tablename = $field->getJoinTable();
$fieldname = "$tablename$offset.$matching";
}
$value = $expr->right();
$sql .= $value->getSQL($field, $left->modifyName($fieldname), $expr->op(), $expr->not());
}
if ($this->context == ExprContext::DOCUMENT)
{
$moffset=0;
foreach($this->metadata as $expr)
{
$moffset++;
if ($offset++)
{
$sql .= " $op\n " ;
}
$field = $expr->left();
$value = $expr->right();
$sql .= $value->getSQL($field, "dfl$moffset.value", $expr->getOp());
}
}
$config = KTConfig::getSingleton();
$maxSqlResults = $config->get('search/maxSqlResults', 1000);
$sql .= "limit $maxSqlResults";
return $sql;
}
public function getRanking($result)
{
$ranker = RankManager::get();
$score = 0;
foreach($result as $col=>$val)
{
if ($val + 0 == 0)
{
// we are not interested if the expression failed
continue;
}
if (substr($col, 0, 4) == 'expr' && is_numeric(substr($col, 4)))
{
$exprno = substr($col, 4);
if ($exprno <= count($this->db))
{
$expr = $this->db[$exprno-1];
$left=$expr->left();
$score += $ranker->scoreField($left->getTable(), 'T', $left->getField());
}
else
{
$exprno -= count($this->db);
$expr = $this->metadata[$exprno-1];
$left=$expr->left();
$score += $ranker->scoreField($left->getTable(), 'M', $left->getField());
}
}
}
return $score;
}
public function getResultText($result)
{
$text = array();
foreach($result as $col=>$val)
{
if (substr($col, 0, 4) == 'expr' && is_numeric(substr($col, 4)))
{
if ($val + 0 == 0)
{
// we are not interested if the expression failed
continue;
}
$exprno = substr($col, 4);
if ($exprno <= count($this->db))
{
$expr = $this->db[$exprno-1];
}
else
{
$exprno -= count($this->db);
$expr = $this->metadata[$exprno-1];
}
$text[] = (string) $expr;
}
}
return '(' . implode(') AND (', $text) . ')';
}
}
class OpExpr extends Expr
{
/**
* The left side of the expression
*
* @var Expr
*/
protected $left_expr;
/**
* The operator on the left and right
*
* @var ExprOp
*/
protected $op;
/**
* The right side of the expression
*
* @var Expr
*/
protected $right_expr;
/**
* This indicates that the expression is negative
*
* @var boolean
*/
protected $not;
protected $point;
protected $has_text;
protected $has_db;
private $debug = false;
// protected $flattened;
protected $results;
public function setResults($results)
{
$this->results=$results;
}
public function getResults()
{
return $this->results;
}
public function setHasDb($value=true)
{
$this->has_db=$value;
}
public function setHasText($value=true)
{
$this->has_text=$value;
}
public function setContext($context)
{
parent::setContext($context);
$this->left()->setContext($context);
$this->right()->setContext($context);
}
public function getHasDb()
{
return $this->has_db;
}
public function getHasText()
{
return $this->has_text;
}
public function setPoint($point)
{
$this->point = $point;
/* if (!is_null($point))
{
$this->flattened = new FlattenedGroup($this);
}
else
{
if (!is_null($this->flattened))
{
unset($this->flattened);
}
$this->flattened = null;
}*/
}
public function getPoint()
{
return $this->point;
}
public function hasSameOpAs($expr)
{
return $this->op() == $expr->op();
}
public static function rewriteString(&$left, &$op, &$right, $not=false)
{
if ($right->isValueExpr())
{
$value = $right->getValue();
}
else
{
$value = $right;
}
$text = array();
preg_match_all('/[\']([^\']*)[\']/',$value, $matches);
foreach($matches[0] as $item)
{
$text [] = $item;
$value = str_replace($item, '', $value);
}
$matches = explode(' ', $value);
foreach($matches as $item)
{
if (empty($item)) continue;
$text[] = $item;
}
if (count($text) == 1)
{
return;
}
$doctext = $left;
$left = new OpExpr($doctext, $op, new ValueExpr($text[0]));
for($i=1;$i<count($text);$i++)
{
if ($i==1)
{
$right = new OpExpr($doctext, $op, new ValueExpr($text[$i]));
}
else
{
$join = new OpExpr($doctext, $op, new ValueExpr($text[$i]));
$right = new OpExpr($join, ExprOp::OP_AND, $right);
}
}
$op = ExprOp::OP_AND;
}
/**
* Constructor for the expression
*
* @param Expr $left
* @param ExprOp $op
* @param Expr $right
*/
public function __construct($left, $op, $right, $not = false)
{
// if left is a string, we assume we should convert it to a FieldExpr
if (is_string($left))
{
$left = new $left;
}
// if right is not an expression, we must convert it!
if (!($right instanceof Expr))
{
$right = new ValueExpr($right);
}
if ($right->isValueListExpr())
{
$right->rewrite($left, $op, $right, $not);
}
else
// rewriting is based on the FieldExpr, and can expand a simple expression
// into something a little bigger.
if ($left->isFieldExpr())
{
$left->rewrite($left, $op, $right, $not);
}
// transformation is required to optimise the expression tree so that
// the queries on the db and full text search are optimised.
if (DefaultOpCollection::isBoolean($op))
{
$this->transform($left, $op, $right, $not);
}
parent::__construct();
$left->setParent($this);
$right->setParent($this);
$this->left_expr=&$left;
$this->op = $op;
$this->right_expr=&$right;
$this->not = $not;
$this->has_text=false;
// $this->setPoint('point');
if ($left->isSearchableText())
{
$this->setHasText();
}
else if ($left->isDBExpr())
{
$this->setHasDb();
}
elseif ($left->isOpExpr())
{
if ($left->getHasText()) { $this->setHasText(); }
if ($left->getHasDb()) { $this->setHasDb(); }
}
if ($right->isOpExpr())
{
if ($right->getHasText()) { $this->setHasText(); }
if ($right->getHasDb()) { $this->setHasDb(); }
}
// $this->flattened=null;
// $left_op, etc indicates that $left expression is a logical expression
$left_op = ($left->isOpExpr() && DefaultOpCollection::isBoolean($left));
$right_op = ($right->isOpExpr() && DefaultOpCollection::isBoolean($right));
// check which trees match
$left_op_match = ($left_op && $this->hasSameOpAs($left)) ;
$right_op_match = ($right_op && $this->hasSameOpAs($left)) ;
$point = null;
if ($left_op_match && $right_op_match) { $point = 'point'; }
$left_op_match_flex = $left_op_match || ($left->isOpExpr());
$right_op_match_flex = $right_op_match || ($right->isOpExpr());
if ($left_op_match_flex && $right_op_match_flex) { $point = 'point'; }
if (!is_null($point))
{
if ($left_op_match && $left->getPoint() == 'point') { $left->setPoint(null); }
if ($right_op_match && $right->getPoint() == 'point') { $right->setPoint(null); }
if ($left->isMergePoint() && is_null($right->getPoint())) { $right->setPoint('point'); }
if ($right->isMergePoint() && is_null($left->getPoint())) { $left->setPoint('point'); }
if ($left->isMergePoint() || $right->isMergePoint())
{
$point = 'merge';
if (!$left->isMergePoint()) { $left->setPoint('point'); }
if (!$right->isMergePoint()) { $right->setPoint('point'); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -