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

Add an example event listener, improve documentation, and add a commit discovery event

Summary: Improve documentation around Phabricator events.

Test Plan: Generated and read documentation. Ran test script.

Reviewers: btrahan, jungejason

Reviewed By: jungejason

CC: aran

Maniphest Tasks: T1092

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

+322 -10
+57
scripts/util/emit_test_event.php
··· 1 + #!/usr/bin/env php 2 + <?php 3 + 4 + /* 5 + * Copyright 2012 Facebook, Inc. 6 + * 7 + * Licensed under the Apache License, Version 2.0 (the "License"); 8 + * you may not use this file except in compliance with the License. 9 + * You may obtain a copy of the License at 10 + * 11 + * http://www.apache.org/licenses/LICENSE-2.0 12 + * 13 + * Unless required by applicable law or agreed to in writing, software 14 + * distributed under the License is distributed on an "AS IS" BASIS, 15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 + * See the License for the specific language governing permissions and 17 + * limitations under the License. 18 + */ 19 + 20 + $root = dirname(dirname(dirname(__FILE__))); 21 + require_once $root.'/scripts/__init_script__.php'; 22 + 23 + $args = new PhutilArgumentParser($argv); 24 + $args->setTagline('emit a test event'); 25 + $args->setSynopsis(<<<EOHELP 26 + **emit_test_event.php** [--listen listener] ... 27 + Emit a test event after installing any specified __listener__s. 28 + EOHELP 29 + ); 30 + $args->parseStandardArguments(); 31 + $args->parse( 32 + array( 33 + array( 34 + 'name' => 'listen', 35 + 'param' => 'listener', 36 + 'repeat' => true, 37 + ), 38 + )); 39 + 40 + $console = PhutilConsole::getConsole(); 41 + foreach ($args->getArg('listen') as $listener) { 42 + $console->writeOut("Installing '%s'...\n", $listener); 43 + newv($listener, array())->register(); 44 + } 45 + 46 + 47 + $console->writeOut("Emitting event...\n"); 48 + 49 + PhutilEventEngine::dispatchEvent( 50 + new PhabricatorEvent( 51 + PhabricatorEventType::TYPE_TEST_DIDRUNTEST, 52 + array( 53 + 'time' => time(), 54 + ))); 55 + 56 + $console->writeOut("Done.\n"); 57 + exit(0);
+4
src/__phutil_library_map__.php
··· 632 632 'PhabricatorEvent' => 'infrastructure/events/PhabricatorEvent.php', 633 633 'PhabricatorEventEngine' => 'infrastructure/events/PhabricatorEventEngine.php', 634 634 'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php', 635 + 'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php', 635 636 'PhabricatorFeedBuilder' => 'applications/feed/builder/PhabricatorFeedBuilder.php', 636 637 'PhabricatorFeedConstants' => 'applications/feed/constants/PhabricatorFeedConstants.php', 637 638 'PhabricatorFeedController' => 'applications/feed/controller/PhabricatorFeedController.php', ··· 1647 1648 'PhabricatorErrorExample' => 'PhabricatorUIExample', 1648 1649 'PhabricatorEvent' => 'PhutilEvent', 1649 1650 'PhabricatorEventType' => 'PhutilEventType', 1651 + 'PhabricatorExampleEventListener' => 'PhutilEventListener', 1650 1652 'PhabricatorFeedController' => 'PhabricatorController', 1651 1653 'PhabricatorFeedDAO' => 'PhabricatorLiskDAO', 1652 1654 'PhabricatorFeedPublicStreamController' => 'PhabricatorFeedController', 1655 + 'PhabricatorFeedQuery' => 'PhabricatorIDPagedPolicyQuery', 1656 + 'PhabricatorFeedStory' => 'PhabricatorPolicyInterface', 1653 1657 'PhabricatorFeedStoryAggregate' => 'PhabricatorFeedStory', 1654 1658 'PhabricatorFeedStoryAudit' => 'PhabricatorFeedStory', 1655 1659 'PhabricatorFeedStoryCommit' => 'PhabricatorFeedStory',
+9
src/applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php
··· 374 374 } 375 375 376 376 $this->setCache($repository, $commit_identifier); 377 + 378 + PhutilEventEngine::dispatchEvent( 379 + new PhabricatorEvent( 380 + PhabricatorEventType::TYPE_DIFFUSION_DIDDISCOVERCOMMIT, 381 + array( 382 + 'repository' => $repository, 383 + 'commit' => $commit, 384 + ))); 385 + 377 386 } catch (AphrontQueryDuplicateKeyException $ex) { 378 387 $commit->killTransaction(); 379 388 // Ignore. This can happen because we discover the same new commit
+177 -5
src/docs/userguide/events.diviner
··· 9 9 to certain things happening (like a Maniphest Task being edited) and run custom 10 10 code to perform logging, synchronize with other systems, or modify workflows. 11 11 12 - NOTE: This feature is new and experimental, so few events are available and 13 - things might not be completely stable. 12 + These listeners are PHP classes which you install beside Phabricator, and which 13 + Phabricator loads at runtime and runs in-process. They are the most direct and 14 + powerful way to respond to events. 15 + 16 + = Installing Event Listeners = 17 + 18 + To install event listeners, follow these steps: 19 + 20 + - Write a listener class which extends @{class:PhutilEventListener}. 21 + - Add it to a libphutil library, or create a new library (for instructions, 22 + see @{article:libphutil Libraries User Guide}. 23 + - Configure Phabricator to load the library by adding it to `load-libraries` 24 + in the Phabricator config. 25 + - Configure Phabricator to install the event listener by adding the class 26 + name to `events.listeners` in the Phabricator config. 27 + 28 + You can verify your listener is registered in the "Events" tab of DarkConsole. 29 + It should appear at the top under "Registered Event Listeners". You can also 30 + see any events the page emitted there. For details on DarkConsole, see 31 + @{article:Using DarkConsole}. 32 + 33 + = Example Listener = 34 + 35 + Phabricator includes an example event listener, 36 + @{class:PhabricatorExampleEventListener}, which may be useful as a starting 37 + point in developing your own listeners. This listener listens for a test 38 + event that is emitted by the script `scripts/util/emit_test_event.php`. 39 + 40 + If you run this script normally, it should output something like this: 41 + 42 + $ ./scripts/util/emit_test_event.php 43 + Emitting event... 44 + Done. 45 + 46 + This is because there are no listeners for the event, so nothing reacts to it 47 + when it is emitted. You can add the example listener by either adding it to 48 + your `events.listeners` configuration or with the `--listen` command-line flag: 49 + 50 + $ ./scripts/util/emit_test_event.php --listen PhabricatorExampleEventListener 51 + Installing 'PhabricatorExampleEventListener'... 52 + Emitting event... 53 + PhabricatorExampleEventListener got test event at 1341344566 54 + Done. 55 + 56 + This time, the listener was installed and had its callback invoked when the 57 + test event was emitted. 14 58 15 59 = Available Events = 16 60 17 - == PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK == 61 + You can find a list of all Phabricator events in @{class:PhabricatorEventType}. 62 + 63 + == All Events == 64 + 65 + The special constant `PhutilEventType::TYPE_ALL` will let you listen for all 66 + events. Normally, you want to listen only to specific events, but if you're 67 + writing a generic handler you can listen to all events with this constant 68 + rather than by enumerating each event. 69 + 70 + == Maniphest: Will Edit Task == 71 + 72 + The constant for this event is 73 + `PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK`. 18 74 19 75 This event is dispatched before a task is edited, and allows you to respond to 20 76 or alter the edit. Data available on this event: ··· 26 82 - ##mail## If this edit originates from email, the 27 83 @{class:PhabricatorMetaMTAReceivedMail} object. 28 84 29 - == PhabricatorEventType::TYPE_DIFFERENTIAL_WILLSENDMAIL == 85 + This is similar to the next event (did edit task) but occurs before the edit 86 + begins. 87 + 88 + == Maniphest: Did Edit Task == 89 + 90 + The constant for this event is 91 + `PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK`. 92 + 93 + This event is dispatched after a task is edited, and allows you to react to the 94 + edit. Data available on this event: 95 + 96 + - ##task## The @{class:ManiphestTask} that was edited. 97 + - ##transactions## The list of edits (objects of class 98 + @{class:ManiphestTransaction}) that were applied. 99 + - ##new## A boolean indicating if this task was newly created. 100 + - ##mail## If this edit originates from email, the 101 + @{class:PhabricatorMetaMTAReceivedMail} object. 102 + 103 + This is similar to the previous event (will edit task) but occurs after the 104 + edit completes. 105 + 106 + == Differential: Will Send Mail == 107 + 108 + The constant for this event is 109 + `PhabricatorEventType::TYPE_DIFFERENTIAL_WILLSENDMAIL` 30 110 31 111 This event is dispatched before Differential sends an email, and allows you to 32 112 edit the message that will be sent. Data available on this event: 33 113 34 114 - ##mail## The @{class:PhabricatorMetaMTAMail} being edited. 35 115 36 - == PhabricatorEventType::TYPE_DIFFERENTIAL_WILLMARKGENERATED == 116 + == Differential: Will Mark Generated == 117 + 118 + The constant for this event is 119 + `PhabricatorEventType::TYPE_DIFFERENTIAL_WILLMARKGENERATED`. 37 120 38 121 This event is dispatched before Differential decides if a file is generated (and 39 122 doesn't need to be reviewed) or not. Data available on this event: ··· 41 124 - ##corpus## Body of the file. 42 125 - ##is_generated## Boolean indicating if this file should be treated as 43 126 generated. 127 + 128 + == Diffusion: Did Discover Commit == 129 + 130 + The constant for this event is 131 + `PhabricatorEventType::TYPE_DIFFUSION_DIDDISCOVERCOMMIT`. 132 + 133 + This event is dispatched when the daemons discover a commit for the first time. 134 + This event happens very early in the pipeline, and not all commit information 135 + will be available yet. Data available on this event: 136 + 137 + - `commit` The @{class:PhabricatorRepositoryCommit} that was discovered. 138 + - `repository` The @{class:PhabricatorRepository} the commit was discovered 139 + in. 140 + 141 + == Edge: Will Edit Edges == 142 + 143 + NOTE: Edge events are low-level events deep in the core. It is more difficult to 144 + correct implement listeners for these events than for higher-level events. 145 + 146 + The constant for this event is 147 + `PhabricatorEventType::TYPE_EDGE_WILLEDITEDGES`. 148 + 149 + This event is dispatched before @{class:PhabricatorEdgeEditor} makes an edge 150 + edit. 151 + 152 + - `id` An identifier for this edit operation. 153 + - `add` A list of dictionaries, each representing a new edge. 154 + - `rem` A list of dictionaries, each representing a removed edge. 155 + 156 + This is similar to the next event (did edit edges) but occurs before the 157 + edit begins. 158 + 159 + == Edge: Did Edit Edges == 160 + 161 + The constant for this event is 162 + `PhabricatorEventType::TYPE_EDGE_DIDEDITEDGES`. 163 + 164 + This event is dispatched after @{class:PhabricatorEdgeEditor} makes an edge 165 + edit, but before it commits the transactions. Data available on this event: 166 + 167 + - `id` An identifier for this edit operation. This is the same ID as 168 + the one included in the corresponding "will edit edges" event. 169 + - `add` A list of dictionaries, each representing a new edge. 170 + - `rem` A list of dictionaries, each representing a removed edge. 171 + 172 + This is similar to the previous event (will edit edges) but occurs after the 173 + edit completes. 174 + 175 + == Test: Did Run Test == 176 + 177 + The constant for this event is 178 + `PhabricatorEventType::TYPE_TEST_DIDRUNTEST`. 179 + 180 + This is a test event for testing event listeners. See above for details. 181 + 182 + = Debugging Listeners = 183 + 184 + If you're having problems with your listener, try these steps: 185 + 186 + - If you're getting an error about Phabricator being unable to find the 187 + listener class, make sure you've added it to a libphutil library and 188 + configured Phabricator to load the library with `load-libraries`. 189 + - Make sure the listener is registered. It should appear in the "Events" tab 190 + of DarkConsole. If it's not there, you may have forgotten to add it to 191 + `events.listeners`. 192 + - Make sure it calls `listen()` on the right events in its `register()` 193 + method. If you don't listen for the events you're interested in, you 194 + won't get a callback. 195 + - Make sure the events you're listening for are actually happening. If they 196 + occur on a normal page they should appear in the "Events" tab of 197 + DarkConsole. If they occur on a POST, you could add a `phlog()` 198 + to the source code near the event and check your error log to make sure the 199 + code ran. 200 + - You can check if your callback is getting invoked by adding `phlog()` with 201 + a message and checking the error log. 202 + - You can try listening to `PhutilEventType::TYPE_ALL` instead of a specific 203 + event type to get all events, to narrow down whether problems are caused 204 + by the types of events you're listening to. 205 + - You can edit the `emit_test_event.php` script to emit other types of 206 + events instead, to test that your listener reacts to them properly. You 207 + might have to use fake data, but this gives you an easy way to test the 208 + at least the basics. 209 + 210 + = Next Steps = 211 + 212 + Continue by: 213 + 214 + - taking a look at @{class:PhabricatorExampleEventListener}; or 215 + - building a library with @{article:@{article:libphutil Libraries User Guide}.
+4
src/infrastructure/events/PhabricatorEvent.php
··· 16 16 * limitations under the License. 17 17 */ 18 18 19 + 20 + /** 21 + * @group events 22 + */ 19 23 final class PhabricatorEvent extends PhutilEvent { 20 24 21 25 private $user;
+3
src/infrastructure/events/PhabricatorEventEngine.php
··· 16 16 * limitations under the License. 17 17 */ 18 18 19 + /** 20 + * @group events 21 + */ 19 22 final class PhabricatorEventEngine { 20 23 21 24 public static function initialize() {
+52
src/infrastructure/events/PhabricatorExampleEventListener.php
··· 1 + <?php 2 + 3 + /* 4 + * Copyright 2012 Facebook, Inc. 5 + * 6 + * Licensed under the Apache License, Version 2.0 (the "License"); 7 + * you may not use this file except in compliance with the License. 8 + * You may obtain a copy of the License at 9 + * 10 + * http://www.apache.org/licenses/LICENSE-2.0 11 + * 12 + * Unless required by applicable law or agreed to in writing, software 13 + * distributed under the License is distributed on an "AS IS" BASIS, 14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 + * See the License for the specific language governing permissions and 16 + * limitations under the License. 17 + */ 18 + 19 + /** 20 + * Example event listener. For details about installing Phabricator event hooks, 21 + * refer to @{article:Events User Guide: Installing Event Listeners}. 22 + * 23 + * @group events 24 + */ 25 + final class PhabricatorExampleEventListener extends PhutilEventListener { 26 + 27 + public function register() { 28 + // When your listener is installed, its register() method will be called. 29 + // You should listen() to any events you are interested in here. 30 + 31 + $this->listen(PhabricatorEventType::TYPE_TEST_DIDRUNTEST); 32 + } 33 + 34 + public function handleEvent(PhutilEvent $event) { 35 + // When an event you have called listen() for in your register() method 36 + // occurs, this method will be invoked. You should respond to the event. 37 + 38 + // In this case, we just echo a message out so the event test script will 39 + // do something visible. 40 + 41 + $console = PhutilConsole::getConsole(); 42 + $console->writeOut( 43 + "PhabricatorExampleEventListener got test event at %d\n", 44 + $event->getValue('time')); 45 + } 46 + 47 + } 48 + 49 + 50 + 51 + 52 +
+16 -5
src/infrastructure/events/constant/PhabricatorEventType.php
··· 16 16 * limitations under the License. 17 17 */ 18 18 19 + /** 20 + * For detailed explanations of these events, see 21 + * @{article:Events User Guide: Installing Event Listeners}. 22 + * 23 + * @group events 24 + */ 19 25 final class PhabricatorEventType extends PhutilEventType { 20 26 21 - const TYPE_MANIPHEST_WILLEDITTASK = 'maniphest.willEditTask'; 22 - const TYPE_MANIPHEST_DIDEDITTASK = 'maniphest.didEditTask'; 23 - const TYPE_DIFFERENTIAL_WILLSENDMAIL = 'differential.willSendMail'; 27 + const TYPE_MANIPHEST_WILLEDITTASK = 'maniphest.willEditTask'; 28 + const TYPE_MANIPHEST_DIDEDITTASK = 'maniphest.didEditTask'; 29 + 30 + const TYPE_DIFFERENTIAL_WILLSENDMAIL = 'differential.willSendMail'; 24 31 const TYPE_DIFFERENTIAL_WILLMARKGENERATED = 'differential.willMarkGenerated'; 25 32 26 - const TYPE_EDGE_WILLEDITEDGES = 'edge.willEditEdges'; 27 - const TYPE_EDGE_DIDEDITEDGES = 'edge.didEditEdges'; 33 + const TYPE_DIFFUSION_DIDDISCOVERCOMMIT = 'diffusion.didDiscoverCommit'; 34 + 35 + const TYPE_EDGE_WILLEDITEDGES = 'edge.willEditEdges'; 36 + const TYPE_EDGE_DIDEDITEDGES = 'edge.didEditEdges'; 37 + 38 + const TYPE_TEST_DIDRUNTEST = 'test.didRunTest'; 28 39 29 40 }