Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2893175
DifferentialRevisionReviewersTransaction.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
12 KB
Referenced Files
None
Subscribers
None
DifferentialRevisionReviewersTransaction.php
View Options
<?php
final
class
DifferentialRevisionReviewersTransaction
extends
DifferentialRevisionTransactionType
{
const
TRANSACTIONTYPE
=
'differential.revision.reviewers'
;
const
EDITKEY
=
'reviewers'
;
public
function
generateOldValue
(
$object
)
{
$reviewers
=
$object
->
getReviewers
(
)
;
$reviewers
=
mpull
(
$reviewers
,
'getReviewerStatus'
,
'getReviewerPHID'
)
;
return
$reviewers
;
}
public
function
generateNewValue
(
$object
,
$value
)
{
$actor
=
$this
->
getActor
(
)
;
$datasource
=
id
(
new
DifferentialBlockingReviewerDatasource
(
)
)
->
setViewer
(
$actor
)
;
$reviewers
=
$this
->
generateOldValue
(
$object
)
;
$old_reviewers
=
$reviewers
;
// First, remove any reviewers we're getting rid of.
$rem
=
idx
(
$value
,
'-'
,
array
(
)
)
;
$rem
=
$datasource
->
evaluateTokens
(
$rem
)
;
foreach
(
$rem
as
$spec
)
{
if
(
!
is_array
(
$spec
)
)
{
$phid
=
$spec
;
}
else
{
$phid
=
$spec
[
'phid'
]
;
}
unset
(
$reviewers
[
$phid
]
)
;
}
$add
=
idx
(
$value
,
'+'
,
array
(
)
)
;
$add
=
$datasource
->
evaluateTokens
(
$add
)
;
$add_map
=
array
(
)
;
foreach
(
$add
as
$spec
)
{
if
(
!
is_array
(
$spec
)
)
{
$phid
=
$spec
;
$status
=
DifferentialReviewerStatus
::
STATUS_ADDED
;
}
else
{
$phid
=
$spec
[
'phid'
]
;
$status
=
$spec
[
'type'
]
;
}
$add_map
[
$phid
]
=
$status
;
}
$set
=
idx
(
$value
,
'='
,
null
)
;
if
(
$set
!==
null
)
{
$set
=
$datasource
->
evaluateTokens
(
$set
)
;
foreach
(
$set
as
$spec
)
{
if
(
!
is_array
(
$spec
)
)
{
$phid
=
$spec
;
$status
=
DifferentialReviewerStatus
::
STATUS_ADDED
;
}
else
{
$phid
=
$spec
[
'phid'
]
;
$status
=
$spec
[
'type'
]
;
}
$add_map
[
$phid
]
=
$status
;
}
// We treat setting reviewers as though they were being added to an
// empty list, so we can share more code between pathways.
$reviewers
=
array
(
)
;
}
$status_blocking
=
DifferentialReviewerStatus
::
STATUS_BLOCKING
;
foreach
(
$add_map
as
$phid
=>
$new_status
)
{
$old_status
=
idx
(
$old_reviewers
,
$phid
)
;
// If we have an old status and this didn't make the reviewer blocking
// or nonblocking, just retain the old status. This makes sure we don't
// throw away rejects, accepts, etc.
if
(
$old_status
)
{
$was_blocking
=
(
$old_status
==
$status_blocking
)
;
$now_blocking
=
(
$new_status
==
$status_blocking
)
;
$is_block
=
(
$now_blocking
&&
!
$was_blocking
)
;
$is_unblock
=
(
!
$now_blocking
&&
$was_blocking
)
;
if
(
!
$is_block
&&
!
$is_unblock
)
{
$reviewers
[
$phid
]
=
$old_status
;
continue
;
}
}
$reviewers
[
$phid
]
=
$new_status
;
}
return
$reviewers
;
}
public
function
getTransactionHasEffect
(
$object
,
$old
,
$new
)
{
// At least for now, we ignore transactions which ONLY reorder reviewers
// without making any actual changes.
ksort
(
$old
)
;
ksort
(
$new
)
;
return
(
$old
!==
$new
)
;
}
public
function
applyExternalEffects
(
$object
,
$value
)
{
$src_phid
=
$object
->
getPHID
(
)
;
$old
=
$this
->
generateOldValue
(
$object
)
;
$new
=
$value
;
$rem
=
array_diff_key
(
$old
,
$new
)
;
$table
=
new
DifferentialReviewer
(
)
;
$table_name
=
$table
->
getTableName
(
)
;
$conn
=
$table
->
establishConnection
(
'w'
)
;
if
(
$rem
)
{
queryfx
(
$conn
,
'DELETE FROM %T WHERE revisionPHID = %s AND reviewerPHID IN (%Ls)'
,
$table_name
,
$src_phid
,
array_keys
(
$rem
)
)
;
}
if
(
$new
)
{
$reviewers
=
$table
->
loadAllWhere
(
'revisionPHID = %s AND reviewerPHID IN (%Ls)'
,
$src_phid
,
array_keys
(
$new
)
)
;
$reviewers
=
mpull
(
$reviewers
,
null
,
'getReviewerPHID'
)
;
foreach
(
$new
as
$dst_phid
=>
$status
)
{
$old_status
=
idx
(
$old
,
$dst_phid
)
;
if
(
$old_status
===
$status
)
{
continue
;
}
$reviewer
=
idx
(
$reviewers
,
$dst_phid
)
;
if
(
!
$reviewer
)
{
$reviewer
=
id
(
new
DifferentialReviewer
(
)
)
->
setRevisionPHID
(
$src_phid
)
->
setReviewerPHID
(
$dst_phid
)
;
}
$reviewer
->
setReviewerStatus
(
$status
)
;
try
{
$reviewer
->
save
(
)
;
}
catch
(
AphrontDuplicateKeyQueryException
$ex
)
{
// At least for now, just ignore it if we lost a race.
}
}
}
}
public
function
getTitle
(
)
{
return
$this
->
renderReviewerEditTitle
(
false
)
;
}
public
function
getTitleForFeed
(
)
{
return
$this
->
renderReviewerEditTitle
(
true
)
;
}
private
function
renderReviewerEditTitle
(
$is_feed
)
{
$old
=
$this
->
getOldValue
(
)
;
$new
=
$this
->
getNewValue
(
)
;
$rem
=
array_diff_key
(
$old
,
$new
)
;
$add
=
array_diff_key
(
$new
,
$old
)
;
$rem_phids
=
array_keys
(
$rem
)
;
$add_phids
=
array_keys
(
$add
)
;
$total_count
=
count
(
$rem
)
+
count
(
$add
)
;
$parts
=
array
(
)
;
if
(
$rem
&&
$add
)
{
if
(
$is_feed
)
{
$parts
[
]
=
pht
(
'%s edited %s reviewer(s) for %s, added %s: %s; removed %s: %s.'
,
$this
->
renderAuthor
(
)
,
new
PhutilNumber
(
$total_count
)
,
$this
->
renderObject
(
)
,
phutil_count
(
$add_phids
)
,
$this
->
renderHandleList
(
$add_phids
)
,
phutil_count
(
$rem_phids
)
,
$this
->
renderHandleList
(
$rem_phids
)
)
;
}
else
{
$parts
[
]
=
pht
(
'%s edited %s reviewer(s), added %s: %s; removed %s: %s.'
,
$this
->
renderAuthor
(
)
,
new
PhutilNumber
(
$total_count
)
,
phutil_count
(
$add_phids
)
,
$this
->
renderHandleList
(
$add_phids
)
,
phutil_count
(
$rem_phids
)
,
$this
->
renderHandleList
(
$rem_phids
)
)
;
}
}
else
if
(
$add
)
{
if
(
$is_feed
)
{
$parts
[
]
=
pht
(
'%s added %s reviewer(s) for %s: %s.'
,
$this
->
renderAuthor
(
)
,
phutil_count
(
$add_phids
)
,
$this
->
renderObject
(
)
,
$this
->
renderHandleList
(
$add_phids
)
)
;
}
else
{
$parts
[
]
=
pht
(
'%s added %s reviewer(s): %s.'
,
$this
->
renderAuthor
(
)
,
phutil_count
(
$add_phids
)
,
$this
->
renderHandleList
(
$add_phids
)
)
;
}
}
else
if
(
$rem
)
{
if
(
$is_feed
)
{
$parts
[
]
=
pht
(
'%s removed %s reviewer(s) for %s: %s.'
,
$this
->
renderAuthor
(
)
,
phutil_count
(
$rem_phids
)
,
$this
->
renderObject
(
)
,
$this
->
renderHandleList
(
$rem_phids
)
)
;
}
else
{
$parts
[
]
=
pht
(
'%s removed %s reviewer(s): %s.'
,
$this
->
renderAuthor
(
)
,
phutil_count
(
$rem_phids
)
,
$this
->
renderHandleList
(
$rem_phids
)
)
;
}
}
$status_blocking
=
DifferentialReviewerStatus
::
STATUS_BLOCKING
;
$blocks
=
array
(
)
;
$unblocks
=
array
(
)
;
foreach
(
$new
as
$phid
=>
$new_status
)
{
$old_status
=
idx
(
$old
,
$phid
)
;
if
(
!
$old_status
)
{
continue
;
}
$was_blocking
=
(
$old_status
==
$status_blocking
)
;
$now_blocking
=
(
$new_status
==
$status_blocking
)
;
$is_block
=
(
$now_blocking
&&
!
$was_blocking
)
;
$is_unblock
=
(
!
$now_blocking
&&
$was_blocking
)
;
if
(
$is_block
)
{
$blocks
[
]
=
$phid
;
}
if
(
$is_unblock
)
{
$unblocks
[
]
=
$phid
;
}
}
$total_count
=
count
(
$blocks
)
+
count
(
$unblocks
)
;
if
(
$blocks
&&
$unblocks
)
{
if
(
$is_feed
)
{
$parts
[
]
=
pht
(
'%s changed %s blocking reviewer(s) for %s, added %s: %s; removed '
.
'%s: %s.'
,
$this
->
renderAuthor
(
)
,
new
PhutilNumber
(
$total_count
)
,
$this
->
renderObject
(
)
,
phutil_count
(
$blocks
)
,
$this
->
renderHandleList
(
$blocks
)
,
phutil_count
(
$unblocks
)
,
$this
->
renderHandleList
(
$unblocks
)
)
;
}
else
{
$parts
[
]
=
pht
(
'%s changed %s blocking reviewer(s), added %s: %s; removed %s: %s.'
,
$this
->
renderAuthor
(
)
,
new
PhutilNumber
(
$total_count
)
,
phutil_count
(
$blocks
)
,
$this
->
renderHandleList
(
$blocks
)
,
phutil_count
(
$unblocks
)
,
$this
->
renderHandleList
(
$unblocks
)
)
;
}
}
else
if
(
$blocks
)
{
if
(
$is_feed
)
{
$parts
[
]
=
pht
(
'%s added %s blocking reviewer(s) for %s: %s.'
,
$this
->
renderAuthor
(
)
,
phutil_count
(
$blocks
)
,
$this
->
renderObject
(
)
,
$this
->
renderHandleList
(
$blocks
)
)
;
}
else
{
$parts
[
]
=
pht
(
'%s added %s blocking reviewer(s): %s.'
,
$this
->
renderAuthor
(
)
,
phutil_count
(
$blocks
)
,
$this
->
renderHandleList
(
$blocks
)
)
;
}
}
else
if
(
$unblocks
)
{
if
(
$is_feed
)
{
$parts
[
]
=
pht
(
'%s removed %s blocking reviewer(s) for %s: %s.'
,
$this
->
renderAuthor
(
)
,
phutil_count
(
$unblocks
)
,
$this
->
renderObject
(
)
,
$this
->
renderHandleList
(
$unblocks
)
)
;
}
else
{
$parts
[
]
=
pht
(
'%s removed %s blocking reviewer(s): %s.'
,
$this
->
renderAuthor
(
)
,
phutil_count
(
$unblocks
)
,
$this
->
renderHandleList
(
$unblocks
)
)
;
}
}
if
(
$this
->
isTextMode
(
)
)
{
return
implode
(
' '
,
$parts
)
;
}
else
{
return
phutil_implode_html
(
' '
,
$parts
)
;
}
}
public
function
validateTransactions
(
$object
,
array
$xactions
)
{
$actor
=
$this
->
getActor
(
)
;
$errors
=
array
(
)
;
if
(
!
$xactions
)
{
// If we aren't applying new reviewer transactions, just bail. We need
// reviewers to be attached to the revision continue validation, and
// they won't always be (for example, when mentioning a revision).
return
$errors
;
}
$author_phid
=
$object
->
getAuthorPHID
(
)
;
$config_self_accept_key
=
'differential.allow-self-accept'
;
$allow_self_accept
=
PhabricatorEnv
::
getEnvConfig
(
$config_self_accept_key
)
;
$old
=
$this
->
generateOldValue
(
$object
)
;
foreach
(
$xactions
as
$xaction
)
{
$new
=
$this
->
generateNewValue
(
$object
,
$xaction
->
getNewValue
(
)
)
;
$add
=
array_diff_key
(
$new
,
$old
)
;
if
(
!
$add
)
{
continue
;
}
$objects
=
id
(
new
PhabricatorObjectQuery
(
)
)
->
setViewer
(
$actor
)
->
withPHIDs
(
array_keys
(
$add
)
)
->
execute
(
)
;
$objects
=
mpull
(
$objects
,
null
,
'getPHID'
)
;
foreach
(
$add
as
$phid
=>
$status
)
{
if
(
!
isset
(
$objects
[
$phid
]
)
)
{
$errors
[
]
=
$this
->
newInvalidError
(
pht
(
'Reviewer "%s" is not a valid object.'
,
$phid
)
,
$xaction
)
;
continue
;
}
switch
(
phid_get_type
(
$phid
)
)
{
case
PhabricatorPeopleUserPHIDType
::
TYPECONST
:
case
PhabricatorOwnersPackagePHIDType
::
TYPECONST
:
case
PhabricatorProjectProjectPHIDType
::
TYPECONST
:
break
;
default
:
$errors
[
]
=
$this
->
newInvalidError
(
pht
(
'Reviewer "%s" must be a user, a package, or a project.'
,
$phid
)
,
$xaction
)
;
continue
2
;
}
// NOTE: This weird behavior around commandeering is a bit unorthodox,
// but this restriction is an unusual one.
$is_self
=
(
$phid
===
$author_phid
)
;
if
(
$is_self
&&
!
$allow_self_accept
)
{
if
(
!
$xaction
->
getIsCommandeerSideEffect
(
)
)
{
$errors
[
]
=
$this
->
newInvalidError
(
pht
(
'The author of a revision can not be a reviewer.'
)
,
$xaction
)
;
continue
;
}
}
}
}
return
$errors
;
}
public
function
getTransactionTypeForConduit
(
$xaction
)
{
return
'reviewers'
;
}
public
function
getFieldValuesForConduit
(
$xaction
,
$data
)
{
$old_value
=
$xaction
->
getOldValue
(
)
;
$new_value
=
$xaction
->
getNewValue
(
)
;
$status_blocking
=
DifferentialReviewerStatus
::
STATUS_BLOCKING
;
$add_phids
=
array_diff_key
(
$new_value
,
$old_value
)
;
foreach
(
$add_phids
as
$add_phid
=>
$value
)
{
$add_phids
[
$add_phid
]
=
array
(
'operation'
=>
'add'
,
'phid'
=>
$add_phid
,
'oldStatus'
=>
null
,
'newStatus'
=>
$value
,
'isBlocking'
=>
(
$value
===
$status_blocking
)
,
)
;
}
$rem_phids
=
array_diff_key
(
$old_value
,
$new_value
)
;
foreach
(
$rem_phids
as
$rem_phid
=>
$value
)
{
$rem_phids
[
$rem_phid
]
=
array
(
'operation'
=>
'remove'
,
'phid'
=>
$rem_phid
,
'oldStatus'
=>
$value
,
'newStatus'
=>
null
,
'isBlocking'
=>
false
,
)
;
}
$mod_phids
=
array_intersect_key
(
$old_value
,
$new_value
)
;
foreach
(
$mod_phids
as
$mod_phid
=>
$ignored
)
{
$old
=
$old_value
[
$mod_phid
]
;
$new
=
$new_value
[
$mod_phid
]
;
if
(
$old
===
$new
)
{
unset
(
$mod_phids
[
$mod_phid
]
)
;
continue
;
}
$mod_phids
[
$mod_phid
]
=
array
(
'operation'
=>
'update'
,
'phid'
=>
$mod_phid
,
'oldStatus'
=>
$old
,
'newStatus'
=>
$new
,
'isBlocking'
=>
(
$new
===
$status_blocking
)
,
)
;
}
$all_ops
=
$add_phids
+
$rem_phids
+
$mod_phids
;
$all_ops
=
array_select_keys
(
$all_ops
,
$new_value
)
+
$all_ops
;
$all_ops
=
array_values
(
$all_ops
)
;
return
array
(
'operations'
=>
$all_ops
,
)
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sun, Jan 19, 18:01 (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1127207
Default Alt Text
DifferentialRevisionReviewersTransaction.php (12 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment