Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Зуев Егор
/
wiki.dev
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Authored by
Dan Brown
2016-05-15 13:41:18 +0100
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Commit
8d80e7311cf4166b5c9597dc793a8f53b13fd7f3
8d80e731
1 parent
79320695
Added tag searching to search interfaces
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
117 additions
and
12 deletions
app/Entity.php
app/Repos/BookRepo.php
app/Repos/ChapterRepo.php
app/Repos/EntityRepo.php
app/Repos/PageRepo.php
resources/views/pages/page-display.blade.php
app/Entity.php
View file @
8d80e73
...
...
@@ -157,9 +157,13 @@ class Entity extends Ownable
* @param string[] array $wheres
* @return mixed
*/
public
static
function
fullTextSearchQuery
(
$fieldsToSearch
,
$terms
,
$wheres
=
[])
public
function
fullTextSearchQuery
(
$fieldsToSearch
,
$terms
,
$wheres
=
[])
{
$exactTerms
=
[];
if
(
count
(
$terms
)
===
0
)
{
$search
=
$this
;
$orderBy
=
'updated_at'
;
}
else
{
foreach
(
$terms
as
$key
=>
$term
)
{
$term
=
htmlentities
(
$term
,
ENT_QUOTES
);
$term
=
preg_replace
(
'/[+\-><\(\)~*\"@]+/'
,
' '
,
$term
);
...
...
@@ -186,19 +190,21 @@ class Entity extends Ownable
}
});
}
$orderBy
=
'title_relevance'
;
};
// Add additional where terms
foreach
(
$wheres
as
$whereTerm
)
{
$search
->
where
(
$whereTerm
[
0
],
$whereTerm
[
1
],
$whereTerm
[
2
]);
}
// Load in relations
if
(
static
::
isA
(
'page'
))
{
if
(
$this
->
isA
(
'page'
))
{
$search
=
$search
->
with
(
'book'
,
'chapter'
,
'createdBy'
,
'updatedBy'
);
}
else
if
(
static
::
isA
(
'chapter'
))
{
}
else
if
(
$this
->
isA
(
'chapter'
))
{
$search
=
$search
->
with
(
'book'
);
}
return
$search
->
orderBy
(
'title_relevance'
,
'desc'
);
return
$search
->
orderBy
(
$orderBy
,
'desc'
);
}
}
...
...
app/Repos/BookRepo.php
View file @
8d80e73
...
...
@@ -286,8 +286,9 @@ class BookRepo extends EntityRepo
public
function
getBySearch
(
$term
,
$count
=
20
,
$paginationAppends
=
[])
{
$terms
=
$this
->
prepareSearchTerms
(
$term
);
$books
=
$this
->
permissionService
->
enforceBookRestrictions
(
$this
->
book
->
fullTextSearchQuery
([
'name'
,
'description'
],
$terms
))
->
paginate
(
$count
)
->
appends
(
$paginationAppends
);
$bookQuery
=
$this
->
permissionService
->
enforceBookRestrictions
(
$this
->
book
->
fullTextSearchQuery
([
'name'
,
'description'
],
$terms
));
$bookQuery
=
$this
->
addAdvancedSearchQueries
(
$bookQuery
,
$term
);
$books
=
$bookQuery
->
paginate
(
$count
)
->
appends
(
$paginationAppends
);
$words
=
join
(
'|'
,
explode
(
' '
,
preg_quote
(
trim
(
$term
),
'/'
)));
foreach
(
$books
as
$book
)
{
//highlight
...
...
app/Repos/ChapterRepo.php
View file @
8d80e73
...
...
@@ -168,8 +168,9 @@ class ChapterRepo extends EntityRepo
public
function
getBySearch
(
$term
,
$whereTerms
=
[],
$count
=
20
,
$paginationAppends
=
[])
{
$terms
=
$this
->
prepareSearchTerms
(
$term
);
$chapters
=
$this
->
permissionService
->
enforceChapterRestrictions
(
$this
->
chapter
->
fullTextSearchQuery
([
'name'
,
'description'
],
$terms
,
$whereTerms
))
->
paginate
(
$count
)
->
appends
(
$paginationAppends
);
$chapterQuery
=
$this
->
permissionService
->
enforceChapterRestrictions
(
$this
->
chapter
->
fullTextSearchQuery
([
'name'
,
'description'
],
$terms
,
$whereTerms
));
$chapterQuery
=
$this
->
addAdvancedSearchQueries
(
$chapterQuery
,
$term
);
$chapters
=
$chapterQuery
->
paginate
(
$count
)
->
appends
(
$paginationAppends
);
$words
=
join
(
'|'
,
explode
(
' '
,
preg_quote
(
trim
(
$term
),
'/'
)));
foreach
(
$chapters
as
$chapter
)
{
//highlight
...
...
app/Repos/EntityRepo.php
View file @
8d80e73
...
...
@@ -6,6 +6,7 @@ use BookStack\Entity;
use
BookStack\Page
;
use
BookStack\Services\PermissionService
;
use
BookStack\User
;
use
Illuminate\Support\Facades\Log
;
class
EntityRepo
{
...
...
@@ -31,6 +32,12 @@ class EntityRepo
protected
$permissionService
;
/**
* Acceptable operators to be used in a query
* @var array
*/
protected
$queryOperators
=
[
'<='
,
'>='
,
'='
,
'<'
,
'>'
,
'like'
,
'!='
];
/**
* EntityService constructor.
*/
public
function
__construct
()
...
...
@@ -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
;
}
}
...
...
app/Repos/PageRepo.php
View file @
8d80e73
...
...
@@ -245,8 +245,9 @@ class PageRepo extends EntityRepo
public
function
getBySearch
(
$term
,
$whereTerms
=
[],
$count
=
20
,
$paginationAppends
=
[])
{
$terms
=
$this
->
prepareSearchTerms
(
$term
);
$pages
=
$this
->
permissionService
->
enforcePageRestrictions
(
$this
->
page
->
fullTextSearchQuery
([
'name'
,
'text'
],
$terms
,
$whereTerms
))
->
paginate
(
$count
)
->
appends
(
$paginationAppends
);
$pageQuery
=
$this
->
permissionService
->
enforcePageRestrictions
(
$this
->
page
->
fullTextSearchQuery
([
'name'
,
'text'
],
$terms
,
$whereTerms
));
$pageQuery
=
$this
->
addAdvancedSearchQueries
(
$pageQuery
,
$term
);
$pages
=
$pageQuery
->
paginate
(
$count
)
->
appends
(
$paginationAppends
);
// Add highlights to page text.
$words
=
join
(
'|'
,
explode
(
' '
,
preg_quote
(
trim
(
$term
),
'/'
)));
...
...
resources/views/pages/page-display.blade.php
View file @
8d80e73
...
...
@@ -8,8 +8,8 @@
<table>
@foreach($page->tags as $tag)
<tr
class=
"tag"
>
<td
@
if
(!$
tag-
>
value) colspan="2" @endif>
{{ $tag->name }}
</td>
@if($tag->value)
<td
class=
"tag-value"
>
{{$tag->value}}
</td>
@endif
<td
@
if
(!$
tag-
>
value) colspan="2" @endif>
<a
href=
"/search/all?term=%5B{{ urlencode($tag->name) }}%5D"
>
{{ $tag->name }}
</a>
</td>
@if($tag->value)
<td
class=
"tag-value"
>
<a
href=
"/search/all?term=%5B{{ urlencode($tag->name) }}%3D{{ urlencode($tag->value) }}%5D"
>
{{$tag->value}}
</a>
</td>
@endif
</tr>
@endforeach
</table>
...
...
Please
register
or
sign in
to post a comment