@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.

Move handle fetching into tokenizer Datasources

Summary:
Ref T7689. This serves two goals:

- I want to remove Controller->loadViewerHandles(). A nontrivial number of these callsites are loading handles to pass to tokenizers. Since tokenizers need to take strings eventually anyway, we can do less work by letting them take PHIDs now.
- A few changes out, I want tokenizers to accept parameterized tokens (like `viewer()`, `members(differential)`, etc.), so the `setValues()` signature needs to change eventually anyway.

I made this work and converted a handful of callsites as an example; upcoming changes will convert more.

Test Plan:
- Viewed Almanac binding editor; used "Interface".
- Edited Almanac services; used "Projects".
- Edited Almanac devices; used "Projects".
- Searched for commits; used "Auditors"; "Commit Authors", "Repositories".
- Searched for calendar events; used "Created By"; used "Invited".

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T7689

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

+79 -73
+2 -7
src/applications/almanac/controller/AlmanacBindingEditController.php
··· 82 82 } 83 83 } 84 84 85 - $interface_handles = array(); 86 - if ($v_interface) { 87 - $interface_handles = $this->loadViewerHandles($v_interface); 88 - } 89 - 90 85 $form = id(new AphrontFormView()) 91 86 ->setUser($viewer) 92 - ->appendChild( 87 + ->appendControl( 93 88 id(new AphrontFormTokenizerControl()) 94 89 ->setName('interfacePHIDs') 95 90 ->setLabel('Interface') 96 91 ->setLimit(1) 97 92 ->setDatasource(new AlmanacInterfaceDatasource()) 98 - ->setValue($interface_handles) 93 + ->setValue($v_interface) 99 94 ->setError($e_interface)) 100 95 ->appendChild( 101 96 id(new AphrontFormSubmitControl())
+2 -8
src/applications/almanac/controller/AlmanacDeviceEditController.php
··· 107 107 ->setObject($device) 108 108 ->execute(); 109 109 110 - if ($v_projects) { 111 - $project_handles = $this->loadViewerHandles($v_projects); 112 - } else { 113 - $project_handles = array(); 114 - } 115 - 116 110 $form = id(new AphrontFormView()) 117 111 ->setUser($viewer) 118 112 ->appendChild( ··· 133 127 ->setPolicyObject($device) 134 128 ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) 135 129 ->setPolicies($policies)) 136 - ->appendChild( 130 + ->appendControl( 137 131 id(new AphrontFormTokenizerControl()) 138 132 ->setLabel(pht('Projects')) 139 133 ->setName('projects') 140 - ->setValue($project_handles) 134 + ->setValue($v_projects) 141 135 ->setDatasource(new PhabricatorProjectDatasource())) 142 136 ->appendChild( 143 137 id(new AphrontFormSubmitControl())
+2 -8
src/applications/almanac/controller/AlmanacServiceEditController.php
··· 122 122 ->setObject($service) 123 123 ->execute(); 124 124 125 - if ($v_projects) { 126 - $project_handles = $this->loadViewerHandles($v_projects); 127 - } else { 128 - $project_handles = array(); 129 - } 130 - 131 125 $form = id(new AphrontFormView()) 132 126 ->setUser($viewer) 133 127 ->addHiddenInput('edit', true) ··· 150 144 ->setPolicyObject($service) 151 145 ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) 152 146 ->setPolicies($policies)) 153 - ->appendChild( 147 + ->appendControl( 154 148 id(new AphrontFormTokenizerControl()) 155 149 ->setLabel(pht('Projects')) 156 150 ->setName('projects') 157 - ->setValue($project_handles) 151 + ->setValue($v_projects) 158 152 ->setDatasource(new PhabricatorProjectDatasource())) 159 153 ->appendChild( 160 154 id(new AphrontFormSubmitControl())
+13 -25
src/applications/audit/query/PhabricatorCommitSearchEngine.php
··· 82 82 $audit_status = $saved->getParameter('auditStatus', null); 83 83 $repository_phids = $saved->getParameter('repositoryPHIDs', array()); 84 84 85 - $phids = array_mergev( 86 - array( 87 - $auditor_phids, 88 - $commit_author_phids, 89 - $repository_phids, 90 - )); 91 - 92 - $handles = id(new PhabricatorHandleQuery()) 93 - ->setViewer($this->requireViewer()) 94 - ->withPHIDs($phids) 95 - ->execute(); 96 - 97 85 $form 98 - ->appendChild( 86 + ->appendControl( 99 87 id(new AphrontFormTokenizerControl()) 100 88 ->setDatasource(new DiffusionAuditorDatasource()) 101 89 ->setName('auditorPHIDs') 102 90 ->setLabel(pht('Auditors')) 103 - ->setValue(array_select_keys($handles, $auditor_phids))) 104 - ->appendChild( 91 + ->setValue($auditor_phids)) 92 + ->appendControl( 105 93 id(new AphrontFormTokenizerControl()) 106 94 ->setDatasource(new PhabricatorPeopleDatasource()) 107 95 ->setName('authors') 108 96 ->setLabel(pht('Commit Authors')) 109 - ->setValue(array_select_keys($handles, $commit_author_phids))) 97 + ->setValue($commit_author_phids)) 110 98 ->appendChild( 111 99 id(new AphrontFormSelectControl()) 112 - ->setName('auditStatus') 113 - ->setLabel(pht('Audit Status')) 114 - ->setOptions($this->getAuditStatusOptions()) 115 - ->setValue($audit_status)) 116 - ->appendChild( 100 + ->setName('auditStatus') 101 + ->setLabel(pht('Audit Status')) 102 + ->setOptions($this->getAuditStatusOptions()) 103 + ->setValue($audit_status)) 104 + ->appendControl( 117 105 id(new AphrontFormTokenizerControl()) 118 - ->setLabel(pht('Repositories')) 119 - ->setName('repositoryPHIDs') 120 - ->setDatasource(new DiffusionRepositoryDatasource()) 121 - ->setValue(array_select_keys($handles, $repository_phids))); 106 + ->setLabel(pht('Repositories')) 107 + ->setName('repositoryPHIDs') 108 + ->setDatasource(new DiffusionRepositoryDatasource()) 109 + ->setValue($repository_phids)); 122 110 123 111 } 124 112
+4 -20
src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php
··· 87 87 $invited_phids = $saved->getParameter('invitedPHIDs', array()); 88 88 $creator_phids = $saved->getParameter('creatorPHIDs', array()); 89 89 90 - $all_phids = array_merge( 91 - $invited_phids, 92 - $creator_phids); 93 - 94 - if ($all_phids) { 95 - $handles = id(new PhabricatorHandleQuery()) 96 - ->setViewer($this->requireViewer()) 97 - ->withPHIDs($all_phids) 98 - ->execute(); 99 - } else { 100 - $handles = array(); 101 - } 102 - 103 - $invited_handles = array_select_keys($handles, $invited_phids); 104 - $creator_handles = array_select_keys($handles, $creator_phids); 105 - 106 90 $form 107 - ->appendChild( 91 + ->appendControl( 108 92 id(new AphrontFormTokenizerControl()) 109 93 ->setDatasource(new PhabricatorPeopleDatasource()) 110 94 ->setName('creators') 111 95 ->setLabel(pht('Created By')) 112 - ->setValue($creator_handles)) 113 - ->appendChild( 96 + ->setValue($creator_phids)) 97 + ->appendControl( 114 98 id(new AphrontFormTokenizerControl()) 115 99 ->setDatasource(new PhabricatorPeopleDatasource()) 116 100 ->setName('invited') 117 101 ->setLabel(pht('Invited')) 118 - ->setValue($invited_handles)) 102 + ->setValue($invited_phids)) 119 103 ->appendChild( 120 104 id(new AphrontFormDateControl()) 121 105 ->setLabel(pht('Occurs After'))
+22 -1
src/view/form/AphrontFormView.php
··· 12 12 private $shaded = false; 13 13 private $sigils = array(); 14 14 private $metadata; 15 - 15 + private $controls = array(); 16 16 17 17 public function setMetadata($metadata) { 18 18 $this->metadata = $metadata; ··· 87 87 ->appendChild($this->renderChildren()); 88 88 } 89 89 90 + 91 + /** 92 + * Append a control to the form. 93 + * 94 + * This method behaves like @{method:appendChild}, but it only takes 95 + * controls. It will propagate some information from the form to the 96 + * control to simplify rendering. 97 + * 98 + * @param AphrontFormControl Control to append. 99 + * @return this 100 + */ 101 + public function appendControl(AphrontFormControl $control) { 102 + $this->controls[] = $control; 103 + return $this->appendChild($control); 104 + } 105 + 106 + 90 107 public function render() { 91 108 require_celerity_resource('phui-form-view-css'); 109 + 110 + foreach ($this->controls as $control) { 111 + $control->setUser($this->getUser()); 112 + } 92 113 93 114 $layout = $this->buildLayoutView(); 94 115
+34 -4
src/view/form/control/AphrontFormTokenizerControl.php
··· 35 35 $name = $this->getName(); 36 36 $values = nonempty($this->getValue(), array()); 37 37 38 - assert_instances_of($values, 'PhabricatorObjectHandle'); 38 + // Values may either be handles (which are now legacy/deprecated) or 39 + // strings. Load handles for any PHIDs. 40 + $load = array(); 41 + $handles = array(); 42 + $select = array(); 43 + foreach ($values as $value) { 44 + if ($value instanceof PhabricatorObjectHandle) { 45 + $handles[$value->getPHID()] = $value; 46 + $select[] = $value->getPHID(); 47 + } else { 48 + $load[] = $value; 49 + $select[] = $value; 50 + } 51 + } 52 + 53 + // TODO: Once this code path simplifies, move this prefetch to setValue() 54 + // so we can bulk load across multiple controls. 55 + 56 + if ($load) { 57 + $viewer = $this->getUser(); 58 + if (!$viewer) { 59 + // TODO: Clean this up when handles go away. 60 + throw new Exception( 61 + pht('Call setUser() before rendering tokenizer string values.')); 62 + } 63 + $loaded_handles = $viewer->loadHandles($load); 64 + $handles = $handles + iterator_to_array($loaded_handles); 65 + } 66 + 67 + // Reorder the list into input order. 68 + $handles = array_select_keys($handles, $select); 39 69 40 70 if ($this->getID()) { 41 71 $id = $this->getID(); ··· 55 85 $template = new AphrontTokenizerTemplateView(); 56 86 $template->setName($name); 57 87 $template->setID($id); 58 - $template->setValue($values); 88 + $template->setValue($handles); 59 89 60 90 $username = null; 61 91 if ($this->user) { ··· 71 101 Javelin::initBehavior('aphront-basic-tokenizer', array( 72 102 'id' => $id, 73 103 'src' => $datasource_uri, 74 - 'value' => mpull($values, 'getFullName', 'getPHID'), 75 - 'icons' => mpull($values, 'getIcon', 'getPHID'), 104 + 'value' => mpull($handles, 'getFullName', 'getPHID'), 105 + 'icons' => mpull($handles, 'getIcon', 'getPHID'), 76 106 'limit' => $this->limit, 77 107 'username' => $username, 78 108 'placeholder' => $placeholder,