Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2983710
PhabricatorApplicationSearchController.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
31 KB
Referenced Files
None
Subscribers
None
PhabricatorApplicationSearchController.php
View Options
<?php
final
class
PhabricatorApplicationSearchController
extends
PhabricatorSearchBaseController
{
private
$searchEngine
;
private
$navigation
;
private
$queryKey
;
private
$preface
;
private
$activeQuery
;
public
function
setPreface
(
$preface
)
{
$this
->
preface
=
$preface
;
return
$this
;
}
public
function
getPreface
(
)
{
return
$this
->
preface
;
}
public
function
setQueryKey
(
$query_key
)
{
$this
->
queryKey
=
$query_key
;
return
$this
;
}
protected
function
getQueryKey
(
)
{
return
$this
->
queryKey
;
}
public
function
setNavigation
(
AphrontSideNavFilterView
$navigation
)
{
$this
->
navigation
=
$navigation
;
return
$this
;
}
protected
function
getNavigation
(
)
{
return
$this
->
navigation
;
}
public
function
setSearchEngine
(
PhabricatorApplicationSearchEngine
$search_engine
)
{
$this
->
searchEngine
=
$search_engine
;
return
$this
;
}
protected
function
getSearchEngine
(
)
{
return
$this
->
searchEngine
;
}
protected
function
getActiveQuery
(
)
{
if
(
!
$this
->
activeQuery
)
{
throw
new
Exception
(
pht
(
'There is no active query yet.'
)
)
;
}
return
$this
->
activeQuery
;
}
protected
function
validateDelegatingController
(
)
{
$parent
=
$this
->
getDelegatingController
(
)
;
if
(
!
$parent
)
{
throw
new
Exception
(
pht
(
'You must delegate to this controller, not invoke it directly.'
)
)
;
}
$engine
=
$this
->
getSearchEngine
(
)
;
if
(
!
$engine
)
{
throw
new
PhutilInvalidStateException
(
'setEngine'
)
;
}
$engine
->
setViewer
(
$this
->
getRequest
(
)
->
getUser
(
)
)
;
$parent
=
$this
->
getDelegatingController
(
)
;
}
public
function
processRequest
(
)
{
$this
->
validateDelegatingController
(
)
;
$query_action
=
$this
->
getRequest
(
)
->
getURIData
(
'queryAction'
)
;
if
(
$query_action
==
'export'
)
{
return
$this
->
processExportRequest
(
)
;
}
if
(
$query_action
===
'customize'
)
{
return
$this
->
processCustomizeRequest
(
)
;
}
$key
=
$this
->
getQueryKey
(
)
;
if
(
$key
==
'edit'
)
{
return
$this
->
processEditRequest
(
)
;
}
else
{
return
$this
->
processSearchRequest
(
)
;
}
}
private
function
processSearchRequest
(
)
{
$parent
=
$this
->
getDelegatingController
(
)
;
$request
=
$this
->
getRequest
(
)
;
$user
=
$request
->
getUser
(
)
;
$engine
=
$this
->
getSearchEngine
(
)
;
$nav
=
$this
->
getNavigation
(
)
;
if
(
!
$nav
)
{
$nav
=
$this
->
buildNavigation
(
)
;
}
if
(
$request
->
isFormPost
(
)
)
{
$saved_query
=
$engine
->
buildSavedQueryFromRequest
(
$request
)
;
$engine
->
saveQuery
(
$saved_query
)
;
return
id
(
new
AphrontRedirectResponse
(
)
)
->
setURI
(
$engine
->
getQueryResultsPageURI
(
$saved_query
->
getQueryKey
(
)
)
.
'#R'
)
;
}
$named_query
=
null
;
$run_query
=
true
;
$query_key
=
$this
->
queryKey
;
if
(
$this
->
queryKey
==
'advanced'
)
{
$run_query
=
false
;
$query_key
=
$request
->
getStr
(
'query'
)
;
}
else
if
(
!
phutil_nonempty_string
(
$this
->
queryKey
)
)
{
$found_query_data
=
false
;
if
(
$request
->
isHTTPGet
(
)
||
$request
->
isQuicksand
(
)
)
{
// If this is a GET request and it has some query data, don't
// do anything unless it's only before= or after=. We'll build and
// execute a query from it below. This allows external tools to build
// URIs like "/query/?users=a,b".
$pt_data
=
$request
->
getPassthroughRequestData
(
)
;
$exempt
=
array
(
'before'
=>
true
,
'after'
=>
true
,
'nux'
=>
true
,
'overheated'
=>
true
,
)
;
foreach
(
$pt_data
as
$pt_key
=>
$pt_value
)
{
if
(
isset
(
$exempt
[
$pt_key
]
)
)
{
continue
;
}
$found_query_data
=
true
;
break
;
}
}
if
(
!
$found_query_data
)
{
// Otherwise, there's no query data so just run the user's default
// query for this application.
$query_key
=
$engine
->
getDefaultQueryKey
(
)
;
}
}
if
(
$engine
->
isBuiltinQuery
(
$query_key
)
)
{
$saved_query
=
$engine
->
buildSavedQueryFromBuiltin
(
$query_key
)
;
$named_query
=
idx
(
$engine
->
loadEnabledNamedQueries
(
)
,
$query_key
)
;
}
else
if
(
$query_key
)
{
$saved_query
=
id
(
new
PhabricatorSavedQueryQuery
(
)
)
->
setViewer
(
$user
)
->
withQueryKeys
(
array
(
$query_key
)
)
->
executeOne
(
)
;
if
(
!
$saved_query
)
{
return
new
Aphront404Response
(
)
;
}
$named_query
=
idx
(
$engine
->
loadEnabledNamedQueries
(
)
,
$query_key
)
;
}
else
{
$saved_query
=
$engine
->
buildSavedQueryFromRequest
(
$request
)
;
// Save the query to generate a query key, so "Save Custom Query..." and
// other features like "Bulk Edit" and "Export Data" work correctly.
$engine
->
saveQuery
(
$saved_query
)
;
}
$this
->
activeQuery
=
$saved_query
;
$nav
->
selectFilter
(
'query/'
.
$saved_query
->
getQueryKey
(
)
,
'query/advanced'
)
;
$form
=
id
(
new
AphrontFormView
(
)
)
->
setUser
(
$user
)
->
setAction
(
$request
->
getPath
(
)
)
;
$engine
->
buildSearchForm
(
$form
,
$saved_query
)
;
$errors
=
$engine
->
getErrors
(
)
;
if
(
$errors
)
{
$run_query
=
false
;
}
$submit
=
id
(
new
AphrontFormSubmitControl
(
)
)
->
setValue
(
pht
(
'Search'
)
)
;
if
(
$run_query
&&
!
$named_query
&&
$user
->
isLoggedIn
(
)
)
{
$save_button
=
id
(
new
PHUIButtonView
(
)
)
->
setTag
(
'a'
)
->
setColor
(
PHUIButtonView
::
GREY
)
->
setHref
(
'/search/edit/key/'
.
$saved_query
->
getQueryKey
(
)
.
'/'
)
->
setText
(
pht
(
'Save Query'
)
)
->
setIcon
(
'fa-bookmark'
)
;
$submit
->
addButton
(
$save_button
)
;
}
$form
->
appendChild
(
$submit
)
;
$body
=
array
(
)
;
if
(
$this
->
getPreface
(
)
)
{
$body
[
]
=
$this
->
getPreface
(
)
;
}
if
(
$named_query
)
{
$title
=
$named_query
->
getQueryName
(
)
;
}
else
{
$title
=
pht
(
'Advanced Search'
)
;
}
$header
=
id
(
new
PHUIHeaderView
(
)
)
->
setHeader
(
$title
)
->
setProfileHeader
(
true
)
;
$box
=
id
(
new
PHUIObjectBoxView
(
)
)
->
setHeader
(
$header
)
->
addClass
(
'application-search-results'
)
;
if
(
$run_query
||
$named_query
)
{
$box
->
setShowHide
(
pht
(
'Edit Query'
)
,
pht
(
'Hide Query'
)
,
$form
,
$this
->
getApplicationURI
(
'query/advanced/?query='
.
$query_key
)
,
(
!
$named_query
?
true
:
false
)
)
;
}
else
{
$box
->
setForm
(
$form
)
;
}
$body
[
]
=
$box
;
$more_crumbs
=
null
;
if
(
$run_query
)
{
$exec_errors
=
array
(
)
;
$box
->
setAnchor
(
id
(
new
PhabricatorAnchorView
(
)
)
->
setAnchorName
(
'R'
)
)
;
try
{
$engine
->
setRequest
(
$request
)
;
$query
=
$engine
->
buildQueryFromSavedQuery
(
$saved_query
)
;
$pager
=
$engine
->
newPagerForSavedQuery
(
$saved_query
)
;
$pager
->
readFromRequest
(
$request
)
;
$query
->
setReturnPartialResultsOnOverheat
(
true
)
;
$objects
=
$engine
->
executeQuery
(
$query
,
$pager
)
;
$force_nux
=
$request
->
getBool
(
'nux'
)
;
if
(
!
$objects
||
$force_nux
)
{
$nux_view
=
$this
->
renderNewUserView
(
$engine
,
$force_nux
)
;
}
else
{
$nux_view
=
null
;
}
$is_overflowing
=
$pager
->
willShowPagingControls
(
)
&&
$engine
->
getResultBucket
(
$saved_query
)
;
$force_overheated
=
$request
->
getBool
(
'overheated'
)
;
$is_overheated
=
$query
->
getIsOverheated
(
)
||
$force_overheated
;
if
(
$nux_view
)
{
$box
->
appendChild
(
$nux_view
)
;
}
else
{
$list
=
$engine
->
renderResults
(
$objects
,
$saved_query
)
;
if
(
!
(
$list
instanceof
PhabricatorApplicationSearchResultView
)
)
{
throw
new
Exception
(
pht
(
'SearchEngines must render a "%s" object, but this engine '
.
'(of class "%s") rendered something else ("%s").'
,
'PhabricatorApplicationSearchResultView'
,
get_class
(
$engine
)
,
phutil_describe_type
(
$list
)
)
)
;
}
if
(
$list
->
getObjectList
(
)
)
{
$box
->
setObjectList
(
$list
->
getObjectList
(
)
)
;
}
if
(
$list
->
getTable
(
)
)
{
$box
->
setTable
(
$list
->
getTable
(
)
)
;
}
if
(
$list
->
getInfoView
(
)
)
{
$box
->
setInfoView
(
$list
->
getInfoView
(
)
)
;
}
if
(
$is_overflowing
)
{
$box
->
appendChild
(
$this
->
newOverflowingView
(
)
)
;
}
if
(
$list
->
getContent
(
)
)
{
$box
->
appendChild
(
$list
->
getContent
(
)
)
;
}
if
(
$is_overheated
)
{
$box
->
appendChild
(
$this
->
newOverheatedView
(
$objects
)
)
;
}
$result_header
=
$list
->
getHeader
(
)
;
if
(
$result_header
)
{
$box
->
setHeader
(
$result_header
)
;
$header
=
$result_header
;
}
$actions
=
$list
->
getActions
(
)
;
if
(
$actions
)
{
foreach
(
$actions
as
$action
)
{
$header
->
addActionLink
(
$action
)
;
}
}
$use_actions
=
$engine
->
newUseResultsActions
(
$saved_query
)
;
// TODO: Eventually, modularize all this stuff.
$builtin_use_actions
=
$this
->
newBuiltinUseActions
(
)
;
if
(
$builtin_use_actions
)
{
foreach
(
$builtin_use_actions
as
$builtin_use_action
)
{
$use_actions
[
]
=
$builtin_use_action
;
}
}
if
(
$use_actions
)
{
$use_dropdown
=
$this
->
newUseResultsDropdown
(
$saved_query
,
$use_actions
)
;
$header
->
addActionLink
(
$use_dropdown
)
;
}
$more_crumbs
=
$list
->
getCrumbs
(
)
;
if
(
$pager
->
willShowPagingControls
(
)
)
{
$pager_box
=
id
(
new
PHUIBoxView
(
)
)
->
setColor
(
PHUIBoxView
::
GREY
)
->
addClass
(
'application-search-pager'
)
->
appendChild
(
$pager
)
;
$body
[
]
=
$pager_box
;
}
}
}
catch
(
PhabricatorTypeaheadLoginRequiredException
$ex
)
{
// A specific token requires login. Show login page.
$auth_class
=
PhabricatorAuthApplication
::
class
;
$auth_application
=
PhabricatorApplication
::
getByClass
(
$auth_class
)
;
$login_controller
=
new
PhabricatorAuthStartController
(
)
;
$this
->
setCurrentApplication
(
$auth_application
)
;
return
$this
->
delegateToController
(
$login_controller
)
;
}
catch
(
PhabricatorTypeaheadInvalidTokenException
$ex
)
{
$exec_errors
[
]
=
pht
(
'This query specifies an invalid parameter. Review the '
.
'query parameters and correct errors.'
)
;
}
catch
(
PhutilSearchQueryCompilerSyntaxException
$ex
)
{
$exec_errors
[
]
=
$ex
->
getMessage
(
)
;
}
catch
(
PhabricatorSearchConstraintException
$ex
)
{
$exec_errors
[
]
=
$ex
->
getMessage
(
)
;
}
catch
(
PhabricatorInvalidQueryCursorException
$ex
)
{
$exec_errors
[
]
=
$ex
->
getMessage
(
)
;
}
// The engine may have encountered additional errors during rendering;
// merge them in and show everything.
foreach
(
$engine
->
getErrors
(
)
as
$error
)
{
$exec_errors
[
]
=
$error
;
}
$errors
=
$exec_errors
;
}
if
(
$errors
)
{
$box
->
setFormErrors
(
$errors
,
pht
(
'Query Errors'
)
)
;
}
$crumbs
=
$parent
->
buildApplicationCrumbs
(
)
->
setBorder
(
true
)
;
if
(
$more_crumbs
)
{
$query_uri
=
$engine
->
getQueryResultsPageURI
(
$saved_query
->
getQueryKey
(
)
)
;
$crumbs
->
addTextCrumb
(
$title
,
$query_uri
)
;
foreach
(
$more_crumbs
as
$crumb
)
{
$crumbs
->
addCrumb
(
$crumb
)
;
}
}
else
{
$crumbs
->
addTextCrumb
(
$title
)
;
}
require_celerity_resource
(
'application-search-view-css'
)
;
return
$this
->
newPage
(
)
->
setTitle
(
pht
(
'Query: %s'
,
$title
)
)
->
setCrumbs
(
$crumbs
)
->
setNavigation
(
$nav
)
->
addClass
(
'application-search-view'
)
->
appendChild
(
$body
)
;
}
private
function
processExportRequest
(
)
{
$viewer
=
$this
->
getViewer
(
)
;
$engine
=
$this
->
getSearchEngine
(
)
;
$request
=
$this
->
getRequest
(
)
;
if
(
!
$this
->
canExport
(
)
)
{
return
new
Aphront404Response
(
)
;
}
$query_key
=
$this
->
getQueryKey
(
)
;
if
(
$engine
->
isBuiltinQuery
(
$query_key
)
)
{
$saved_query
=
$engine
->
buildSavedQueryFromBuiltin
(
$query_key
)
;
}
else
if
(
$query_key
)
{
$saved_query
=
id
(
new
PhabricatorSavedQueryQuery
(
)
)
->
setViewer
(
$viewer
)
->
withQueryKeys
(
array
(
$query_key
)
)
->
executeOne
(
)
;
}
else
{
$saved_query
=
null
;
}
if
(
!
$saved_query
)
{
return
new
Aphront404Response
(
)
;
}
$cancel_uri
=
$engine
->
getQueryResultsPageURI
(
$query_key
)
;
$named_query
=
idx
(
$engine
->
loadEnabledNamedQueries
(
)
,
$query_key
)
;
if
(
$named_query
)
{
$filename
=
$named_query
->
getQueryName
(
)
;
$sheet_title
=
$named_query
->
getQueryName
(
)
;
}
else
{
$filename
=
$engine
->
getResultTypeDescription
(
)
;
$sheet_title
=
$engine
->
getResultTypeDescription
(
)
;
}
$filename
=
phutil_utf8_strtolower
(
$filename
)
;
$filename
=
PhabricatorFile
::
normalizeFileName
(
$filename
)
;
$all_formats
=
PhabricatorExportFormat
::
getAllExportFormats
(
)
;
$available_options
=
array
(
)
;
$unavailable_options
=
array
(
)
;
$formats
=
array
(
)
;
$unavailable_formats
=
array
(
)
;
foreach
(
$all_formats
as
$key
=>
$format
)
{
if
(
$format
->
isExportFormatEnabled
(
)
)
{
$available_options
[
$key
]
=
$format
->
getExportFormatName
(
)
;
$formats
[
$key
]
=
$format
;
}
else
{
$unavailable_options
[
$key
]
=
pht
(
'%s (Not Available)'
,
$format
->
getExportFormatName
(
)
)
;
$unavailable_formats
[
$key
]
=
$format
;
}
}
$format_options
=
$available_options
+
$unavailable_options
;
// Try to default to the format the user used last time. If you just
// exported to Excel, you probably want to export to Excel again.
$format_key
=
$this
->
readExportFormatPreference
(
)
;
if
(
!
isset
(
$formats
[
$format_key
]
)
)
{
$format_key
=
head_key
(
$format_options
)
;
}
// Check if this is a large result set or not. If we're exporting a
// large amount of data, we'll build the actual export file in the daemons.
$threshold
=
1000
;
$query
=
$engine
->
buildQueryFromSavedQuery
(
$saved_query
)
;
$pager
=
$engine
->
newPagerForSavedQuery
(
$saved_query
)
;
$pager
->
setPageSize
(
$threshold
+
1
)
;
$objects
=
$engine
->
executeQuery
(
$query
,
$pager
)
;
$object_count
=
count
(
$objects
)
;
$is_large_export
=
(
$object_count
>
$threshold
)
;
$errors
=
array
(
)
;
$e_format
=
null
;
if
(
$request
->
isFormPost
(
)
)
{
$format_key
=
$request
->
getStr
(
'format'
)
;
if
(
isset
(
$unavailable_formats
[
$format_key
]
)
)
{
$unavailable
=
$unavailable_formats
[
$format_key
]
;
$instructions
=
$unavailable
->
getInstallInstructions
(
)
;
$markup
=
id
(
new
PHUIRemarkupView
(
$viewer
,
$instructions
)
)
->
setRemarkupOption
(
PHUIRemarkupView
::
OPTION_PRESERVE_LINEBREAKS
,
false
)
;
return
$this
->
newDialog
(
)
->
setTitle
(
pht
(
'Export Format Not Available'
)
)
->
appendChild
(
$markup
)
->
addCancelButton
(
$cancel_uri
,
pht
(
'Done'
)
)
;
}
$format
=
idx
(
$formats
,
$format_key
)
;
if
(
!
$format
)
{
$e_format
=
pht
(
'Invalid'
)
;
$errors
[
]
=
pht
(
'Choose a valid export format.'
)
;
}
if
(
!
$errors
)
{
$this
->
writeExportFormatPreference
(
$format_key
)
;
$export_engine
=
id
(
new
PhabricatorExportEngine
(
)
)
->
setViewer
(
$viewer
)
->
setSearchEngine
(
$engine
)
->
setSavedQuery
(
$saved_query
)
->
setTitle
(
$sheet_title
)
->
setFilename
(
$filename
)
->
setExportFormat
(
$format
)
;
if
(
$is_large_export
)
{
$job
=
$export_engine
->
newBulkJob
(
$request
)
;
return
id
(
new
AphrontRedirectResponse
(
)
)
->
setURI
(
$job
->
getMonitorURI
(
)
)
;
}
else
{
$file
=
$export_engine
->
exportFile
(
)
;
return
$file
->
newDownloadResponse
(
)
;
}
}
}
$export_form
=
id
(
new
AphrontFormView
(
)
)
->
setViewer
(
$viewer
)
->
appendControl
(
id
(
new
AphrontFormSelectControl
(
)
)
->
setName
(
'format'
)
->
setLabel
(
pht
(
'Format'
)
)
->
setError
(
$e_format
)
->
setValue
(
$format_key
)
->
setOptions
(
$format_options
)
)
;
if
(
$is_large_export
)
{
$submit_button
=
pht
(
'Continue'
)
;
}
else
{
$submit_button
=
pht
(
'Download Data'
)
;
}
return
$this
->
newDialog
(
)
->
setTitle
(
pht
(
'Export Results'
)
)
->
setErrors
(
$errors
)
->
appendForm
(
$export_form
)
->
addCancelButton
(
$cancel_uri
)
->
addSubmitButton
(
$submit_button
)
;
}
private
function
processEditRequest
(
)
{
$parent
=
$this
->
getDelegatingController
(
)
;
$request
=
$this
->
getRequest
(
)
;
$viewer
=
$request
->
getUser
(
)
;
$engine
=
$this
->
getSearchEngine
(
)
;
$nav
=
$this
->
getNavigation
(
)
;
if
(
!
$nav
)
{
$nav
=
$this
->
buildNavigation
(
)
;
}
$named_queries
=
$engine
->
loadAllNamedQueries
(
)
;
$can_global
=
$viewer
->
getIsAdmin
(
)
;
$groups
=
array
(
'personal'
=>
array
(
'name'
=>
pht
(
'Personal Saved Queries'
)
,
'items'
=>
array
(
)
,
'edit'
=>
true
,
)
,
'global'
=>
array
(
'name'
=>
pht
(
'Global Saved Queries'
)
,
'items'
=>
array
(
)
,
'edit'
=>
$can_global
,
)
,
)
;
foreach
(
$named_queries
as
$named_query
)
{
if
(
$named_query
->
isGlobal
(
)
)
{
$group
=
'global'
;
}
else
{
$group
=
'personal'
;
}
$groups
[
$group
]
[
'items'
]
[
]
=
$named_query
;
}
$default_key
=
$engine
->
getDefaultQueryKey
(
)
;
$lists
=
array
(
)
;
foreach
(
$groups
as
$group
)
{
$lists
[
]
=
$this
->
newQueryListView
(
$group
[
'name'
]
,
$group
[
'items'
]
,
$default_key
,
$group
[
'edit'
]
)
;
}
$crumbs
=
$parent
->
buildApplicationCrumbs
(
)
->
addTextCrumb
(
pht
(
'Saved Queries'
)
,
$engine
->
getQueryManagementURI
(
)
)
->
setBorder
(
true
)
;
$nav
->
selectFilter
(
'query/edit'
)
;
$header
=
id
(
new
PHUIHeaderView
(
)
)
->
setHeader
(
pht
(
'Saved Queries'
)
)
->
setProfileHeader
(
true
)
;
$view
=
id
(
new
PHUITwoColumnView
(
)
)
->
setHeader
(
$header
)
->
setFooter
(
$lists
)
;
return
$this
->
newPage
(
)
->
setTitle
(
pht
(
'Saved Queries'
)
)
->
setCrumbs
(
$crumbs
)
->
setNavigation
(
$nav
)
->
appendChild
(
$view
)
;
}
private
function
newQueryListView
(
$list_name
,
array
$named_queries
,
$default_key
,
$can_edit
)
{
$engine
=
$this
->
getSearchEngine
(
)
;
$viewer
=
$this
->
getViewer
(
)
;
$list
=
id
(
new
PHUIObjectItemListView
(
)
)
->
setViewer
(
$viewer
)
;
if
(
$can_edit
)
{
$list_id
=
celerity_generate_unique_node_id
(
)
;
$list
->
setID
(
$list_id
)
;
Javelin
::
initBehavior
(
'search-reorder-queries'
,
array
(
'listID'
=>
$list_id
,
'orderURI'
=>
'/search/order/'
.
get_class
(
$engine
)
.
'/'
,
)
)
;
}
foreach
(
$named_queries
as
$named_query
)
{
$class
=
get_class
(
$engine
)
;
$key
=
$named_query
->
getQueryKey
(
)
;
$item
=
id
(
new
PHUIObjectItemView
(
)
)
->
setHeader
(
$named_query
->
getQueryName
(
)
)
->
setHref
(
$engine
->
getQueryResultsPageURI
(
$key
)
)
;
if
(
$named_query
->
getIsDisabled
(
)
)
{
if
(
$can_edit
)
{
$item
->
setDisabled
(
true
)
;
}
else
{
// If an item is disabled and you don't have permission to edit it,
// just skip it.
continue
;
}
}
if
(
$can_edit
)
{
if
(
$named_query
->
getIsBuiltin
(
)
&&
$named_query
->
getIsDisabled
(
)
)
{
$icon
=
'fa-plus'
;
$disable_name
=
pht
(
'Enable'
)
;
}
else
{
$icon
=
'fa-times'
;
if
(
$named_query
->
getIsBuiltin
(
)
)
{
$disable_name
=
pht
(
'Disable'
)
;
}
else
{
$disable_name
=
pht
(
'Delete'
)
;
}
}
if
(
$named_query
->
getID
(
)
)
{
$disable_href
=
'/search/delete/id/'
.
$named_query
->
getID
(
)
.
'/'
;
}
else
{
$disable_href
=
'/search/delete/key/'
.
$key
.
'/'
.
$class
.
'/'
;
}
$item
->
addAction
(
id
(
new
PHUIListItemView
(
)
)
->
setIcon
(
$icon
)
->
setHref
(
$disable_href
)
->
setRenderNameAsTooltip
(
true
)
->
setName
(
$disable_name
)
->
setWorkflow
(
true
)
)
;
}
$default_disabled
=
$named_query
->
getIsDisabled
(
)
;
$default_icon
=
'fa-thumb-tack'
;
if
(
$default_key
===
$key
)
{
$default_color
=
'green'
;
}
else
{
$default_color
=
null
;
}
$item
->
addAction
(
id
(
new
PHUIListItemView
(
)
)
->
setIcon
(
"{$default_icon} {$default_color}"
)
->
setHref
(
'/search/default/'
.
$key
.
'/'
.
$class
.
'/'
)
->
setRenderNameAsTooltip
(
true
)
->
setName
(
pht
(
'Make Default'
)
)
->
setWorkflow
(
true
)
->
setDisabled
(
$default_disabled
)
)
;
if
(
$can_edit
)
{
if
(
$named_query
->
getIsBuiltin
(
)
)
{
$edit_icon
=
'fa-lock lightgreytext'
;
$edit_disabled
=
true
;
$edit_name
=
pht
(
'Builtin'
)
;
$edit_href
=
null
;
}
else
{
$edit_icon
=
'fa-pencil'
;
$edit_disabled
=
false
;
$edit_name
=
pht
(
'Edit'
)
;
$edit_href
=
'/search/edit/id/'
.
$named_query
->
getID
(
)
.
'/'
;
}
$item
->
addAction
(
id
(
new
PHUIListItemView
(
)
)
->
setIcon
(
$edit_icon
)
->
setHref
(
$edit_href
)
->
setRenderNameAsTooltip
(
true
)
->
setName
(
$edit_name
)
->
setDisabled
(
$edit_disabled
)
)
;
}
$item
->
setGrippable
(
$can_edit
)
;
$item
->
addSigil
(
'named-query'
)
;
$item
->
setMetadata
(
array
(
'queryKey'
=>
$named_query
->
getQueryKey
(
)
,
)
)
;
$list
->
addItem
(
$item
)
;
}
$list
->
setNoDataString
(
pht
(
'No saved queries.'
)
)
;
return
id
(
new
PHUIObjectBoxView
(
)
)
->
setHeaderText
(
$list_name
)
->
setBackground
(
PHUIObjectBoxView
::
BLUE_PROPERTY
)
->
setObjectList
(
$list
)
;
}
public
function
buildApplicationMenu
(
)
{
$menu
=
$this
->
getDelegatingController
(
)
->
buildApplicationMenu
(
)
;
if
(
$menu
instanceof
PHUIApplicationMenuView
)
{
$menu
->
setSearchEngine
(
$this
->
getSearchEngine
(
)
)
;
}
return
$menu
;
}
private
function
buildNavigation
(
)
{
$viewer
=
$this
->
getViewer
(
)
;
$engine
=
$this
->
getSearchEngine
(
)
;
$nav
=
id
(
new
AphrontSideNavFilterView
(
)
)
->
setUser
(
$viewer
)
->
setBaseURI
(
new
PhutilURI
(
$this
->
getApplicationURI
(
)
)
)
;
$engine
->
addNavigationItems
(
$nav
->
getMenu
(
)
)
;
return
$nav
;
}
private
function
renderNewUserView
(
PhabricatorApplicationSearchEngine
$engine
,
$force_nux
)
{
// Don't render NUX if the user has clicked away from the default page.
if
(
phutil_nonempty_string
(
$this
->
getQueryKey
(
)
)
)
{
return
null
;
}
// Don't put NUX in panels because it would be weird.
if
(
$engine
->
isPanelContext
(
)
)
{
return
null
;
}
// Try to render the view itself first, since this should be very cheap
// (just returning some text).
$nux_view
=
$engine
->
renderNewUserView
(
)
;
if
(
!
$nux_view
)
{
return
null
;
}
$query
=
$engine
->
newQuery
(
)
;
if
(
!
$query
)
{
return
null
;
}
// Try to load any object at all. If we can, the application has seen some
// use so we just render the normal view.
if
(
!
$force_nux
)
{
$object
=
$query
->
setViewer
(
PhabricatorUser
::
getOmnipotentUser
(
)
)
->
setLimit
(
1
)
->
setReturnPartialResultsOnOverheat
(
true
)
->
execute
(
)
;
if
(
$object
)
{
return
null
;
}
}
return
$nux_view
;
}
private
function
newUseResultsDropdown
(
PhabricatorSavedQuery
$query
,
array
$dropdown_items
)
{
$viewer
=
$this
->
getViewer
(
)
;
$action_list
=
id
(
new
PhabricatorActionListView
(
)
)
->
setViewer
(
$viewer
)
;
foreach
(
$dropdown_items
as
$dropdown_item
)
{
$action_list
->
addAction
(
$dropdown_item
)
;
}
return
id
(
new
PHUIButtonView
(
)
)
->
setTag
(
'a'
)
->
setHref
(
'#'
)
->
setText
(
pht
(
'Use Results'
)
)
->
setIcon
(
'fa-bars'
)
->
setDropdownMenu
(
$action_list
)
->
addClass
(
'dropdown'
)
;
}
private
function
newOverflowingView
(
)
{
$message
=
pht
(
'The query matched more than one page of results. Results are '
.
'paginated before bucketing, so later pages may contain additional '
.
'results in any bucket.'
)
;
return
id
(
new
PHUIInfoView
(
)
)
->
setSeverity
(
PHUIInfoView
::
SEVERITY_WARNING
)
->
setFlush
(
true
)
->
setTitle
(
pht
(
'Buckets Overflowing'
)
)
->
setErrors
(
array
(
$message
,
)
)
;
}
public
static
function
newOverheatedError
(
$has_results
)
{
$overheated_link
=
phutil_tag
(
'a'
,
array
(
'href'
=>
'https://secure.phabricator.com/T13274'
,
'target'
=>
'_blank'
,
)
,
pht
(
'Learn More'
)
)
;
if
(
$has_results
)
{
$message
=
pht
(
'This query took too long, so only some results are shown. %s'
,
$overheated_link
)
;
}
else
{
$message
=
pht
(
'This query took too long. %s'
,
$overheated_link
)
;
}
return
$message
;
}
private
function
newOverheatedView
(
array
$results
)
{
$message
=
self
::
newOverheatedError
(
(bool)
$results
)
;
return
id
(
new
PHUIInfoView
(
)
)
->
setSeverity
(
PHUIInfoView
::
SEVERITY_WARNING
)
->
setFlush
(
true
)
->
setTitle
(
pht
(
'Query Overheated'
)
)
->
setErrors
(
array
(
$message
,
)
)
;
}
private
function
newBuiltinUseActions
(
)
{
$actions
=
array
(
)
;
$request
=
$this
->
getRequest
(
)
;
$viewer
=
$request
->
getUser
(
)
;
$is_dev
=
PhabricatorEnv
::
getEnvConfig
(
'phabricator.developer-mode'
)
;
$engine
=
$this
->
getSearchEngine
(
)
;
$engine_class
=
get_class
(
$engine
)
;
$query_key
=
$this
->
getActiveQuery
(
)
->
getQueryKey
(
)
;
$can_use
=
$engine
->
canUseInPanelContext
(
)
;
$is_installed
=
PhabricatorApplication
::
isClassInstalledForViewer
(
'PhabricatorDashboardApplication'
,
$viewer
)
;
if
(
$can_use
&&
$is_installed
)
{
$actions
[
]
=
id
(
new
PhabricatorActionView
(
)
)
->
setIcon
(
'fa-dashboard'
)
->
setName
(
pht
(
'Add to Dashboard'
)
)
->
setWorkflow
(
true
)
->
setHref
(
"/dashboard/panel/install/{$engine_class}/{$query_key}/"
)
;
}
if
(
$this
->
canExport
(
)
)
{
$export_uri
=
$engine
->
getExportURI
(
$query_key
)
;
$actions
[
]
=
id
(
new
PhabricatorActionView
(
)
)
->
setIcon
(
'fa-download'
)
->
setName
(
pht
(
'Export Data'
)
)
->
setWorkflow
(
true
)
->
setHref
(
$export_uri
)
;
}
if
(
$is_dev
)
{
$engine
=
$this
->
getSearchEngine
(
)
;
$nux_uri
=
$engine
->
getQueryBaseURI
(
)
;
$nux_uri
=
id
(
new
PhutilURI
(
$nux_uri
)
)
->
replaceQueryParam
(
'nux'
,
true
)
;
$actions
[
]
=
id
(
new
PhabricatorActionView
(
)
)
->
setIcon
(
'fa-user-plus'
)
->
setName
(
pht
(
'DEV: New User State'
)
)
->
setHref
(
$nux_uri
)
;
}
if
(
$is_dev
)
{
$overheated_uri
=
$this
->
getRequest
(
)
->
getRequestURI
(
)
->
replaceQueryParam
(
'overheated'
,
true
)
;
$actions
[
]
=
id
(
new
PhabricatorActionView
(
)
)
->
setIcon
(
'fa-fire'
)
->
setName
(
pht
(
'DEV: Overheated State'
)
)
->
setHref
(
$overheated_uri
)
;
}
return
$actions
;
}
private
function
canExport
(
)
{
$engine
=
$this
->
getSearchEngine
(
)
;
if
(
!
$engine
->
canExport
(
)
)
{
return
false
;
}
// Don't allow logged-out users to perform exports. There's no technical
// or policy reason they can't, but we don't normally give them access
// to write files or jobs. For now, just err on the side of caution.
$viewer
=
$this
->
getViewer
(
)
;
if
(
!
$viewer
->
getPHID
(
)
)
{
return
false
;
}
return
true
;
}
private
function
readExportFormatPreference
(
)
{
$viewer
=
$this
->
getViewer
(
)
;
$export_key
=
PhabricatorExportFormatSetting
::
SETTINGKEY
;
$value
=
$viewer
->
getUserSetting
(
$export_key
)
;
if
(
is_string
(
$value
)
)
{
return
$value
;
}
return
''
;
}
private
function
writeExportFormatPreference
(
$value
)
{
$viewer
=
$this
->
getViewer
(
)
;
$request
=
$this
->
getRequest
(
)
;
if
(
!
$viewer
->
isLoggedIn
(
)
)
{
return
;
}
$export_key
=
PhabricatorExportFormatSetting
::
SETTINGKEY
;
$preferences
=
PhabricatorUserPreferences
::
loadUserPreferences
(
$viewer
)
;
$editor
=
id
(
new
PhabricatorUserPreferencesEditor
(
)
)
->
setActor
(
$viewer
)
->
setContentSourceFromRequest
(
$request
)
->
setContinueOnNoEffect
(
true
)
->
setContinueOnMissingFields
(
true
)
;
$xactions
=
array
(
)
;
$xactions
[
]
=
$preferences
->
newTransaction
(
$export_key
,
$value
)
;
$editor
->
applyTransactions
(
$preferences
,
$xactions
)
;
}
private
function
processCustomizeRequest
(
)
{
$viewer
=
$this
->
getViewer
(
)
;
$engine
=
$this
->
getSearchEngine
(
)
;
$request
=
$this
->
getRequest
(
)
;
$object_phid
=
$request
->
getStr
(
'search.objectPHID'
)
;
$context_phid
=
$request
->
getStr
(
'search.contextPHID'
)
;
// For now, the object can only be a dashboard panel, so just use a panel
// query explicitly.
$object
=
id
(
new
PhabricatorDashboardPanelQuery
(
)
)
->
setViewer
(
$viewer
)
->
withPHIDs
(
array
(
$object_phid
)
)
->
requireCapabilities
(
array
(
PhabricatorPolicyCapability
::
CAN_VIEW
,
PhabricatorPolicyCapability
::
CAN_EDIT
,
)
)
->
executeOne
(
)
;
if
(
!
$object
)
{
return
new
Aphront404Response
(
)
;
}
$object_name
=
pht
(
'%s %s'
,
$object
->
getMonogram
(
)
,
$object
->
getName
(
)
)
;
// Likewise, the context object can only be a dashboard.
if
(
strlen
(
$context_phid
)
)
{
$context
=
id
(
new
PhabricatorDashboardQuery
(
)
)
->
setViewer
(
$viewer
)
->
withPHIDs
(
array
(
$context_phid
)
)
->
executeOne
(
)
;
if
(
!
$context
)
{
return
new
Aphront404Response
(
)
;
}
}
else
{
$context
=
$object
;
}
$done_uri
=
$context
->
getURI
(
)
;
if
(
$request
->
isFormPost
(
)
)
{
$saved_query
=
$engine
->
buildSavedQueryFromRequest
(
$request
)
;
$engine
->
saveQuery
(
$saved_query
)
;
$query_key
=
$saved_query
->
getQueryKey
(
)
;
}
else
{
$query_key
=
$this
->
getQueryKey
(
)
;
if
(
$engine
->
isBuiltinQuery
(
$query_key
)
)
{
$saved_query
=
$engine
->
buildSavedQueryFromBuiltin
(
$query_key
)
;
}
else
if
(
$query_key
)
{
$saved_query
=
id
(
new
PhabricatorSavedQueryQuery
(
)
)
->
setViewer
(
$viewer
)
->
withQueryKeys
(
array
(
$query_key
)
)
->
executeOne
(
)
;
}
else
{
$saved_query
=
null
;
}
}
if
(
!
$saved_query
)
{
return
new
Aphront404Response
(
)
;
}
$form
=
id
(
new
AphrontFormView
(
)
)
->
setViewer
(
$viewer
)
->
addHiddenInput
(
'search.objectPHID'
,
$object_phid
)
->
addHiddenInput
(
'search.contextPHID'
,
$context_phid
)
->
setAction
(
$request
->
getPath
(
)
)
;
$engine
->
buildSearchForm
(
$form
,
$saved_query
)
;
$errors
=
$engine
->
getErrors
(
)
;
if
(
$request
->
isFormPost
(
)
)
{
if
(
!
$errors
)
{
$xactions
=
array
(
)
;
// Since this workflow is currently used only by dashboard panels,
// we can hard-code how the edit works.
$xactions
[
]
=
$object
->
getApplicationTransactionTemplate
(
)
->
setTransactionType
(
PhabricatorDashboardQueryPanelQueryTransaction
::
TRANSACTIONTYPE
)
->
setNewValue
(
$query_key
)
;
$editor
=
$object
->
getApplicationTransactionEditor
(
)
->
setActor
(
$viewer
)
->
setContentSourceFromRequest
(
$request
)
->
setContinueOnNoEffect
(
true
)
->
setContinueOnMissingFields
(
true
)
;
$editor
->
applyTransactions
(
$object
,
$xactions
)
;
return
id
(
new
AphrontRedirectResponse
(
)
)
->
setURI
(
$done_uri
)
;
}
}
return
$this
->
newDialog
(
)
->
setTitle
(
pht
(
'Customize Query: %s'
,
$object_name
)
)
->
setErrors
(
$errors
)
->
setWidth
(
AphrontDialogView
::
WIDTH_FULL
)
->
appendForm
(
$form
)
->
addCancelButton
(
$done_uri
)
->
addSubmitButton
(
pht
(
'Save Changes'
)
)
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Thu, Feb 20, 20:51 (2 d, 2 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1118677
Default Alt Text
PhabricatorApplicationSearchController.php (31 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment