@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Implement PhabricatorProjectInterface for marking that objects can be tagged with projects

Summary: Ref T2628. This makes Transactions understand objects that can have project relationships, extract project mentions, and handle watching.

Test Plan: See next diff.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T2628

Differential Revision: https://secure.phabricator.com/D9340

+121 -7
+3
src/__phutil_library_map__.php
··· 1957 1957 'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php', 1958 1958 'PhabricatorProjectEditorTestCase' => 'applications/project/editor/__tests__/PhabricatorProjectEditorTestCase.php', 1959 1959 'PhabricatorProjectIcon' => 'applications/project/icon/PhabricatorProjectIcon.php', 1960 + 'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php', 1960 1961 'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', 1961 1962 'PhabricatorProjectMembersEditController' => 'applications/project/controller/PhabricatorProjectMembersEditController.php', 1962 1963 'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php', ··· 1975 1976 'PhabricatorProjectTransaction' => 'applications/project/storage/PhabricatorProjectTransaction.php', 1976 1977 'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php', 1977 1978 'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php', 1979 + 'PhabricatorProjectUIEventListener' => 'applications/project/events/PhabricatorProjectUIEventListener.php', 1978 1980 'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php', 1979 1981 'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php', 1980 1982 'PhabricatorQuery' => 'infrastructure/query/PhabricatorQuery.php', ··· 4809 4811 'PhabricatorProjectTransaction' => 'PhabricatorApplicationTransaction', 4810 4812 'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 4811 4813 'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 4814 + 'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener', 4812 4815 'PhabricatorProjectUpdateController' => 'PhabricatorProjectController', 4813 4816 'PhabricatorProjectWatchController' => 'PhabricatorProjectController', 4814 4817 'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions',
+6
src/applications/project/application/PhabricatorApplicationProject.php
··· 32 32 ); 33 33 } 34 34 35 + public function getEventListeners() { 36 + return array( 37 + new PhabricatorProjectUIEventListener(), 38 + ); 39 + } 40 + 35 41 public function getRoutes() { 36 42 return array( 37 43 '/project/' => array(
+59
src/applications/project/events/PhabricatorProjectUIEventListener.php
··· 1 + <?php 2 + 3 + final class PhabricatorProjectUIEventListener 4 + extends PhabricatorEventListener { 5 + 6 + public function register() { 7 + $this->listen(PhabricatorEventType::TYPE_UI_WILLRENDERPROPERTIES); 8 + } 9 + 10 + public function handleEvent(PhutilEvent $event) { 11 + switch ($event->getType()) { 12 + case PhabricatorEventType::TYPE_UI_WILLRENDERPROPERTIES: 13 + $this->handlePropertyEvent($event); 14 + break; 15 + } 16 + } 17 + 18 + private function handlePropertyEvent($event) { 19 + $user = $event->getUser(); 20 + $object = $event->getValue('object'); 21 + 22 + if (!$object || !$object->getPHID()) { 23 + // No object, or the object has no PHID yet.. 24 + return; 25 + } 26 + 27 + if (!($object instanceof PhabricatorProjectInterface)) { 28 + // This object doesn't have projects. 29 + return; 30 + } 31 + 32 + $project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( 33 + $object->getPHID(), 34 + PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT); 35 + if ($project_phids) { 36 + $project_phids = array_reverse($project_phids); 37 + $handles = id(new PhabricatorHandleQuery()) 38 + ->setViewer($user) 39 + ->withPHIDs($project_phids) 40 + ->execute(); 41 + } else { 42 + $handles = array(); 43 + } 44 + 45 + if ($handles) { 46 + $list = array(); 47 + foreach ($handles as $handle) { 48 + $list[] = $handle->renderLink(); 49 + } 50 + $list = phutil_implode_html(phutil_tag('br'), $list); 51 + } else { 52 + $list = phutil_tag('em', array(), pht('None')); 53 + } 54 + 55 + $view = $event->getValue('view'); 56 + $view->addProperty(pht('Projects'), $list); 57 + } 58 + 59 + }
+5
src/applications/project/interface/PhabricatorProjectInterface.php
··· 1 + <?php 2 + 3 + interface PhabricatorProjectInterface { 4 + 5 + }
+41 -7
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 163 163 $types[] = PhabricatorTransactions::TYPE_TOKEN; 164 164 } 165 165 166 + if ($this->object instanceof PhabricatorProjectInterface) { 167 + $types[] = PhabricatorTransactions::TYPE_EDGE; 168 + } 169 + 166 170 return $types; 167 171 } 168 172 ··· 1079 1083 1080 1084 // TODO: For now, this is just a placeholder. 1081 1085 $engine = PhabricatorMarkupEngine::getEngine('extract'); 1086 + $engine->setConfig('viewer', $this->requireActor()); 1082 1087 1083 1088 $block_xactions = $this->expandRemarkupBlockTransactions( 1084 1089 $object, ··· 1098 1103 array $xactions, 1099 1104 $blocks, 1100 1105 PhutilMarkupEngine $engine) { 1101 - return $this->expandCustomRemarkupBlockTransactions( 1106 + 1107 + $block_xactions = $this->expandCustomRemarkupBlockTransactions( 1102 1108 $object, 1103 1109 $xactions, 1104 1110 $blocks, 1105 1111 $engine); 1112 + 1113 + if ($object instanceof PhabricatorProjectInterface) { 1114 + $phids = array(); 1115 + foreach ($blocks as $key => $xaction_blocks) { 1116 + foreach ($xaction_blocks as $block) { 1117 + $engine->markupText($block); 1118 + $phids += $engine->getTextMetadata( 1119 + PhabricatorRemarkupRuleObject::KEY_MENTIONED_OBJECTS, 1120 + array()); 1121 + } 1122 + } 1123 + 1124 + $project_type = PhabricatorProjectPHIDTypeProject::TYPECONST; 1125 + foreach ($phids as $key => $phid) { 1126 + if (phid_get_type($phid) != $project_type) { 1127 + unset($phids[$key]); 1128 + } 1129 + } 1130 + 1131 + if ($phids) { 1132 + $edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT; 1133 + $block_xactions[] = newv(get_class(head($xactions)), array()) 1134 + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 1135 + ->setMetadataValue('edge:type', $edge_type) 1136 + ->setNewValue(array('+' => $phids)); 1137 + } 1138 + } 1139 + 1140 + return $block_xactions; 1106 1141 } 1107 1142 1108 1143 protected function expandCustomRemarkupBlockTransactions( ··· 1899 1934 $has_support = true; 1900 1935 } 1901 1936 1902 - // TODO: This should be some interface which specifies that the object 1903 - // has project associations. 1904 - if ($object instanceof ManiphestTask) { 1937 + // TODO: The Maniphest legacy stuff should get cleaned up here. 1938 + 1939 + if (($object instanceof ManiphestTask) || 1940 + ($object instanceof PhabricatorProjectInterface)) { 1905 1941 1906 - // TODO: This is what normal objects would do, but Maniphest is still 1907 - // behind the times. 1908 - if (false) { 1942 + if ($object instanceof PhabricatorProjectInterface) { 1909 1943 $project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( 1910 1944 $object->getPHID(), 1911 1945 PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT);
+7
src/infrastructure/markup/rule/PhabricatorRemarkupRuleObject.php
··· 7 7 extends PhutilRemarkupRule { 8 8 9 9 const KEY_RULE_OBJECT = 'rule.object'; 10 + const KEY_MENTIONED_OBJECTS = 'rule.object.mentioned'; 10 11 11 12 abstract protected function getObjectNamePrefix(); 12 13 abstract protected function loadObjects(array $ids); ··· 187 188 unset($metadata[$key]); 188 189 } 189 190 } 191 + 192 + $phids = $engine->getTextMetadata(self::KEY_MENTIONED_OBJECTS, array()); 193 + foreach ($objects as $object) { 194 + $phids[$object->getPHID()] = $object->getPHID(); 195 + } 196 + $engine->setTextMetadata(self::KEY_MENTIONED_OBJECTS, $phids); 190 197 191 198 $handles = $this->loadHandles($objects); 192 199 foreach ($metadata as $key => $spec) {