Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F102679887
PhrictionDocumentEditor.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Feb 23, 04:42
Size
11 KB
Mime Type
text/x-php
Expires
Tue, Feb 25, 04:42 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
24395383
Attached To
rPH Phabricator
PhrictionDocumentEditor.php
View Options
<?php
/**
* Create or update Phriction documents.
*/
final
class
PhrictionDocumentEditor
extends
PhabricatorEditor
{
private
$document
;
private
$content
;
private
$newTitle
;
private
$newContent
;
private
$description
;
// For the Feed Story when moving documents
private
$fromDocumentPHID
;
private
function
__construct
()
{
// <restricted>
}
public
static
function
newForSlug
(
$slug
)
{
$slug
=
PhabricatorSlug
::
normalize
(
$slug
);
// TODO: Get rid of this.
$document
=
id
(
new
PhrictionDocument
())->
loadOneWhere
(
'slug = %s'
,
$slug
);
$content
=
null
;
if
(
$document
)
{
$content
=
id
(
new
PhrictionContent
())->
load
(
$document
->
getContentID
());
}
else
{
$document
=
new
PhrictionDocument
();
$document
->
setSlug
(
$slug
);
}
if
(!
$content
)
{
$default_title
=
PhabricatorSlug
::
getDefaultTitle
(
$slug
);
$content
=
new
PhrictionContent
();
$content
->
setSlug
(
$slug
);
$content
->
setTitle
(
$default_title
);
$content
->
setContent
(
''
);
}
$obj
=
new
PhrictionDocumentEditor
();
$obj
->
document
=
$document
;
$obj
->
content
=
$content
;
return
$obj
;
}
public
function
setTitle
(
$title
)
{
$this
->
newTitle
=
$title
;
return
$this
;
}
public
function
setContent
(
$content
)
{
$this
->
newContent
=
$content
;
return
$this
;
}
public
function
setDescription
(
$description
)
{
$this
->
description
=
$description
;
return
$this
;
}
public
function
getDocument
()
{
return
$this
->
document
;
}
public
function
moveAway
(
$new_doc_id
)
{
return
$this
->
execute
(
PhrictionChangeType
::
CHANGE_MOVE_AWAY
,
true
,
$new_doc_id
);
}
public
function
moveHere
(
$old_doc_id
,
$old_doc_phid
)
{
$this
->
fromDocumentPHID
=
$old_doc_phid
;
return
$this
->
execute
(
PhrictionChangeType
::
CHANGE_MOVE_HERE
,
false
,
$old_doc_id
);
}
private
function
execute
(
$change_type
,
$del_new_content
=
true
,
$doc_ref
=
null
)
{
$actor
=
$this
->
requireActor
();
$document
=
$this
->
document
;
$content
=
$this
->
content
;
$new_content
=
$this
->
buildContentTemplate
(
$document
,
$content
);
$new_content
->
setChangeType
(
$change_type
);
if
(
$del_new_content
)
{
$new_content
->
setContent
(
''
);
}
if
(
$doc_ref
)
{
$new_content
->
setChangeRef
(
$doc_ref
);
}
return
$this
->
updateDocument
(
$document
,
$content
,
$new_content
);
}
public
function
delete
()
{
return
$this
->
execute
(
PhrictionChangeType
::
CHANGE_DELETE
,
true
);
}
public
function
stub
()
{
return
$this
->
execute
(
PhrictionChangeType
::
CHANGE_STUB
,
true
);
}
public
function
save
()
{
$actor
=
$this
->
requireActor
();
if
(
$this
->
newContent
===
''
)
{
// If this is an edit which deletes all the content, just treat it as
// a delete. NOTE: null means "don't change the content", not "delete
// the page"! Thus the strict type check.
return
$this
->
delete
();
}
$document
=
$this
->
document
;
$content
=
$this
->
content
;
$new_content
=
$this
->
buildContentTemplate
(
$document
,
$content
);
return
$this
->
updateDocument
(
$document
,
$content
,
$new_content
);
}
private
function
buildContentTemplate
(
PhrictionDocument
$document
,
PhrictionContent
$content
)
{
$new_content
=
new
PhrictionContent
();
$new_content
->
setSlug
(
$document
->
getSlug
());
$new_content
->
setAuthorPHID
(
$this
->
getActor
()->
getPHID
());
$new_content
->
setChangeType
(
PhrictionChangeType
::
CHANGE_EDIT
);
$new_content
->
setTitle
(
coalesce
(
$this
->
newTitle
,
$content
->
getTitle
()));
$new_content
->
setContent
(
coalesce
(
$this
->
newContent
,
$content
->
getContent
()));
if
(
strlen
(
$this
->
description
))
{
$new_content
->
setDescription
(
$this
->
description
);
}
return
$new_content
;
}
private
function
updateDocument
(
$document
,
$content
,
$new_content
)
{
$is_new
=
false
;
if
(!
$document
->
getID
())
{
$is_new
=
true
;
}
$new_content
->
setVersion
(
$content
->
getVersion
()
+
1
);
$change_type
=
$new_content
->
getChangeType
();
switch
(
$change_type
)
{
case
PhrictionChangeType
::
CHANGE_EDIT
:
$doc_status
=
PhrictionDocumentStatus
::
STATUS_EXISTS
;
$feed_action
=
$is_new
?
PhrictionActionConstants
::
ACTION_CREATE
:
PhrictionActionConstants
::
ACTION_EDIT
;
break
;
case
PhrictionChangeType
::
CHANGE_DELETE
:
$doc_status
=
PhrictionDocumentStatus
::
STATUS_DELETED
;
$feed_action
=
PhrictionActionConstants
::
ACTION_DELETE
;
if
(
$is_new
)
{
throw
new
Exception
(
"You can not delete a document which doesn't exist yet!"
);
}
break
;
case
PhrictionChangeType
::
CHANGE_STUB
:
$doc_status
=
PhrictionDocumentStatus
::
STATUS_STUB
;
$feed_action
=
null
;
break
;
case
PhrictionChangeType
::
CHANGE_MOVE_AWAY
:
$doc_status
=
PhrictionDocumentStatus
::
STATUS_MOVED
;
$feed_action
=
null
;
break
;
case
PhrictionChangeType
::
CHANGE_MOVE_HERE
:
$doc_status
=
PhrictionDocumentStatus
::
STATUS_EXISTS
;
$feed_action
=
PhrictionActionConstants
::
ACTION_MOVE_HERE
;
break
;
default
:
throw
new
Exception
(
"Unsupported content change type '{$change_type}'!"
);
}
$document
->
setStatus
(
$doc_status
);
// TODO: This should be transactional.
if
(
$is_new
)
{
$document
->
save
();
}
$new_content
->
setDocumentID
(
$document
->
getID
());
$new_content
->
save
();
$document
->
setContentID
(
$new_content
->
getID
());
$document
->
save
();
$document
->
attachContent
(
$new_content
);
id
(
new
PhabricatorSearchIndexer
())
->
queueDocumentForIndexing
(
$document
->
getPHID
());
// Stub out empty parent documents if they don't exist
$ancestral_slugs
=
PhabricatorSlug
::
getAncestry
(
$document
->
getSlug
());
if
(
$ancestral_slugs
)
{
$ancestors
=
id
(
new
PhrictionDocument
())->
loadAllWhere
(
'slug IN (%Ls)'
,
$ancestral_slugs
);
$ancestors
=
mpull
(
$ancestors
,
null
,
'getSlug'
);
foreach
(
$ancestral_slugs
as
$slug
)
{
// We check for change type to prevent near-infinite recursion
if
(!
isset
(
$ancestors
[
$slug
])
&&
$new_content
->
getChangeType
()
!=
PhrictionChangeType
::
CHANGE_STUB
)
{
id
(
PhrictionDocumentEditor
::
newForSlug
(
$slug
))
->
setActor
(
$this
->
getActor
())
->
setTitle
(
PhabricatorSlug
::
getDefaultTitle
(
$slug
))
->
setContent
(
''
)
->
setDescription
(
pht
(
'Empty Parent Document'
))
->
stub
();
}
}
}
$project_phid
=
null
;
$slug
=
$document
->
getSlug
();
if
(
PhrictionDocument
::
isProjectSlug
(
$slug
))
{
$project
=
id
(
new
PhabricatorProjectQuery
())
->
setViewer
(
$this
->
requireActor
())
->
withPhrictionSlugs
(
array
(
PhrictionDocument
::
getProjectSlugIdentifier
(
$slug
),
))
->
executeOne
();
if
(
$project
)
{
$project_phid
=
$project
->
getPHID
();
}
}
$related_phids
=
array
(
$document
->
getPHID
(),
$this
->
getActor
()->
getPHID
(),
);
if
(
$project_phid
)
{
$related_phids
[]
=
$project_phid
;
}
if
(
$this
->
fromDocumentPHID
)
{
$related_phids
[]
=
$this
->
fromDocumentPHID
;
}
if
(
$feed_action
)
{
$content_str
=
id
(
new
PhutilUTF8StringTruncator
())
->
setMaximumGlyphs
(
140
)
->
truncateString
(
$new_content
->
getContent
());
id
(
new
PhabricatorFeedStoryPublisher
())
->
setRelatedPHIDs
(
$related_phids
)
->
setStoryAuthorPHID
(
$this
->
getActor
()->
getPHID
())
->
setStoryTime
(
time
())
->
setStoryType
(
PhabricatorFeedStoryTypeConstants
::
STORY_PHRICTION
)
->
setStoryData
(
array
(
'phid'
=>
$document
->
getPHID
(),
'action'
=>
$feed_action
,
'content'
=>
$content_str
,
'project'
=>
$project_phid
,
'movedFromPHID'
=>
$this
->
fromDocumentPHID
,
))
->
publish
();
}
// TODO: Migrate to ApplicationTransactions fast, so we get rid of this code
$subscribers
=
PhabricatorSubscribersQuery
::
loadSubscribersForPHID
(
$document
->
getPHID
());
$this
->
sendMailToSubscribers
(
$subscribers
,
$content
);
return
$this
;
}
private
function
getChangeTypeDescription
(
$const
,
$title
)
{
$map
=
array
(
PhrictionChangeType
::
CHANGE_EDIT
=>
pht
(
'Phriction Document %s was edited.'
,
$title
),
PhrictionChangeType
::
CHANGE_DELETE
=>
pht
(
'Phriction Document %s was deleted.'
,
$title
),
PhrictionChangeType
::
CHANGE_MOVE_HERE
=>
pht
(
'Phriction Document %s was moved here.'
,
$title
),
PhrictionChangeType
::
CHANGE_MOVE_AWAY
=>
pht
(
'Phriction Document %s was moved away.'
,
$title
),
PhrictionChangeType
::
CHANGE_STUB
=>
pht
(
'Phriction Document %s was created through child.'
,
$title
),
);
return
idx
(
$map
,
$const
,
pht
(
'Something magical occurred.'
));
}
private
function
sendMailToSubscribers
(
array
$subscribers
,
$old_content
)
{
if
(!
$subscribers
)
{
return
;
}
$author_phid
=
$this
->
getActor
()->
getPHID
();
$document
=
$this
->
document
;
$content
=
$document
->
getContent
();
$slug_uri
=
PhrictionDocument
::
getSlugURI
(
$document
->
getSlug
());
$diff_uri
=
new
PhutilURI
(
'/phriction/diff/'
.
$document
->
getID
().
'/'
);
$prod_uri
=
PhabricatorEnv
::
getProductionURI
(
''
);
$vs_head
=
$diff_uri
->
alter
(
'l'
,
$old_content
->
getVersion
())
->
alter
(
'r'
,
$content
->
getVersion
());
$old_title
=
$old_content
->
getTitle
();
$title
=
$content
->
getTitle
();
$name
=
$this
->
getChangeTypeDescription
(
$content
->
getChangeType
(),
$title
);
$action
=
PhrictionChangeType
::
getChangeTypeLabel
(
$content
->
getChangeType
());
$body
=
array
(
$name
);
// Content may have changed, you never know
if
(
$content
->
getChangeType
()
==
PhrictionChangeType
::
CHANGE_EDIT
)
{
if
(
$old_title
!=
$title
)
{
$body
[]
=
pht
(
'Title was changed from "%s" to "%s"'
,
$old_title
,
$title
);
}
$body
[]
=
pht
(
"Link to new version:
\n
%s"
,
$prod_uri
.
$slug_uri
.
'?v='
.
$content
->
getVersion
());
$body
[]
=
pht
(
"Link to diff:
\n
%s"
,
$prod_uri
.
$vs_head
);
}
else
if
(
$content
->
getChangeType
()
==
PhrictionChangeType
::
CHANGE_MOVE_AWAY
)
{
$target_document
=
id
(
new
PhrictionDocument
())
->
load
(
$content
->
getChangeRef
());
$slug_uri
=
PhrictionDocument
::
getSlugURI
(
$target_document
->
getSlug
());
$body
[]
=
pht
(
"Link to destination document:
\n
%s"
,
$prod_uri
.
$slug_uri
);
}
$body
=
implode
(
"
\n\n
"
,
$body
);
$subject_prefix
=
$this
->
getMailSubjectPrefix
();
$mail
=
new
PhabricatorMetaMTAMail
();
$mail
->
setSubject
(
$name
)
->
setSubjectPrefix
(
$subject_prefix
)
->
setVarySubjectPrefix
(
'['
.
$action
.
']'
)
->
addHeader
(
'Thread-Topic'
,
$name
)
->
setFrom
(
$author_phid
)
->
addTos
(
$subscribers
)
->
setBody
(
$body
)
->
setRelatedPHID
(
$document
->
getPHID
())
->
setIsBulk
(
true
);
$mail
->
saveAndSend
();
}
/* --( For less copy-pasting when switching to ApplicationTransactions )--- */
protected
function
getMailSubjectPrefix
()
{
return
PhabricatorEnv
::
getEnvConfig
(
'metamta.phriction.subject-prefix'
);
}
}
Event Timeline
Log In to Comment