1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-07-30 04:23:11 +03:00

Added tag searching to search interfaces

This commit is contained in:
Dan Brown
2016-05-15 13:41:18 +01:00
parent 7932069535
commit 8d80e7311c
6 changed files with 143 additions and 38 deletions

View File

@ -6,6 +6,7 @@ use BookStack\Entity;
use BookStack\Page;
use BookStack\Services\PermissionService;
use BookStack\User;
use Illuminate\Support\Facades\Log;
class EntityRepo
{
@ -30,6 +31,12 @@ class EntityRepo
*/
protected $permissionService;
/**
* Acceptable operators to be used in a query
* @var array
*/
protected $queryOperators = ['<=', '>=', '=', '<', '>', 'like', '!='];
/**
* EntityService constructor.
*/
@ -163,6 +170,7 @@ class EntityRepo
*/
protected function prepareSearchTerms($termString)
{
$termString = $this->cleanSearchTermString($termString);
preg_match_all('/"(.*?)"/', $termString, $matches);
if (count($matches[1]) > 0) {
$terms = $matches[1];
@ -174,5 +182,93 @@ class EntityRepo
return $terms;
}
/**
* Removes any special search notation that should not
* be used in a full-text search.
* @param $termString
* @return mixed
*/
protected function cleanSearchTermString($termString)
{
// Strip tag searches
$termString = preg_replace('/\[.*?\]/', '', $termString);
// Reduced multiple spacing into single spacing
$termString = preg_replace("/\s{2,}/", " ", $termString);
return $termString;
}
/**
* Get the available query operators as a regex escaped list.
* @return mixed
*/
protected function getRegexEscapedOperators()
{
$escapedOperators = [];
foreach ($this->queryOperators as $operator) {
$escapedOperators[] = preg_quote($operator);
}
return join('|', $escapedOperators);
}
/**
* Parses advanced search notations and adds them to the db query.
* @param $query
* @param $termString
* @return mixed
*/
protected function addAdvancedSearchQueries($query, $termString)
{
$escapedOperators = $this->getRegexEscapedOperators();
// Look for tag searches
preg_match_all("/\[(.*?)((${escapedOperators})(.*?))?\]/", $termString, $tags);
if (count($tags[0]) > 0) {
$this->applyTagSearches($query, $tags);
}
return $query;
}
/**
* Apply extracted tag search terms onto a entity query.
* @param $query
* @param $tags
* @return mixed
*/
protected function applyTagSearches($query, $tags) {
$query->where(function($query) use ($tags) {
foreach ($tags[1] as $index => $tagName) {
$query->whereHas('tags', function($query) use ($tags, $index, $tagName) {
$tagOperator = $tags[3][$index];
$tagValue = $tags[4][$index];
if (!empty($tagOperator) && !empty($tagValue) && in_array($tagOperator, $this->queryOperators)) {
if (is_numeric($tagValue) && $tagOperator !== 'like') {
// We have to do a raw sql query for this since otherwise PDO will quote the value and MySQL will
// search the value as a string which prevents being able to do number-based operations
// on the tag values. We ensure it has a numeric value and then cast it just to be sure.
$tagValue = (float) trim($query->getConnection()->getPdo()->quote($tagValue), "'");
$query->where('name', '=', $tagName)->whereRaw("value ${tagOperator} ${tagValue}");
} else {
$query->where('name', '=', $tagName)->where('value', $tagOperator, $tagValue);
}
} else {
$query->where('name', '=', $tagName);
}
});
}
});
return $query;
}
}
}