[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/docs/user/userguide/ -> events.diviner (source)

   1  @title Events User Guide: Installing Event Listeners
   2  @group userguide
   3  
   4  Using Phabricator event listeners to customize behavior.
   5  
   6  = Overview =
   7  
   8  Phabricator and Arcanist allow you to install custom runtime event listeners
   9  which can react to certain things happening (like a Maniphest Task being edited
  10  or a user creating a new Differential Revision) and run custom code to perform
  11  logging, synchronize with other systems, or modify workflows.
  12  
  13  These listeners are PHP classes which you install beside Phabricator or
  14  Arcanist, and which Phabricator loads at runtime and runs in-process. They
  15  require somewhat more effort upfront than simple configuration switches, but are
  16  the most direct and powerful way to respond to events.
  17  
  18  = Installing Event Listeners (Phabicator) =
  19  
  20  To install event listeners in Phabricator, follow these steps:
  21  
  22    - Write a listener class which extends @{class@libphutil:PhutilEventListener}.
  23    - Add it to a libphutil library, or create a new library (for instructions,
  24      see @{article:libphutil Libraries User Guide}.
  25    - Configure Phabricator to load the library by adding it to `load-libraries`
  26      in the Phabricator config.
  27    - Configure Phabricator to install the event listener by adding the class
  28      name to `events.listeners` in the Phabricator config.
  29  
  30  You can verify your listener is registered in the "Events" tab of DarkConsole.
  31  It should appear at the top under "Registered Event Listeners". You can also
  32  see any events the page emitted there. For details on DarkConsole, see
  33  @{article:Using DarkConsole}.
  34  
  35  = Installing Event Listeners (Arcanist) =
  36  
  37  To install event listeners in Arcanist, follow these steps:
  38  
  39    - Write a listener class which extends @{class@libphutil:PhutilEventListener}.
  40    - Add it to a libphutil library, or create a new library (for instructions,
  41      see @{article:libphutil Libraries User Guide}.
  42    - Configure Phabricator to load the library by adding it to `load`
  43      in the Arcanist config (e.g., `.arcconfig`, or user/global config).
  44    - Configure Arcanist to install the event listener by adding the class
  45      name to `events.listeners` in the Arcanist config.
  46  
  47  You can verify your listener is registered by running any `arc` command with
  48  `--trace`. You should see output indicating your class was registered as an
  49  event listener.
  50  
  51  = Example Listener =
  52  
  53  Phabricator includes an example event listener,
  54  @{class:PhabricatorExampleEventListener}, which may be useful as a starting
  55  point in developing your own listeners. This listener listens for a test
  56  event that is emitted by the script `scripts/util/emit_test_event.php`.
  57  
  58  If you run this script normally, it should output something like this:
  59  
  60    $ ./scripts/util/emit_test_event.php
  61    Emitting event...
  62    Done.
  63  
  64  This is because there are no listeners for the event, so nothing reacts to it
  65  when it is emitted. You can add the example listener by either adding it to
  66  your `events.listeners` configuration or with the `--listen` command-line flag:
  67  
  68    $ ./scripts/util/emit_test_event.php --listen PhabricatorExampleEventListener
  69    Installing 'PhabricatorExampleEventListener'...
  70    Emitting event...
  71    PhabricatorExampleEventListener got test event at 1341344566
  72    Done.
  73  
  74  This time, the listener was installed and had its callback invoked when the
  75  test event was emitted.
  76  
  77  = Available Events =
  78  
  79  You can find a list of all Phabricator events in @{class:PhabricatorEventType}.
  80  
  81  == All Events ==
  82  
  83  The special constant `PhutilEventType::TYPE_ALL` will let you listen for all
  84  events. Normally, you want to listen only to specific events, but if you're
  85  writing a generic handler you can listen to all events with this constant
  86  rather than by enumerating each event.
  87  
  88  == Arcanist Events ==
  89  
  90  Arcanist event constants are listed in @{class@arcanist:ArcanistEventType}.
  91  
  92  All Arcanist events have this data available:
  93  
  94    - `workflow` The active @{class@arcanist:ArcanistWorkflow}.
  95  
  96  == Arcanist: Commit: Will Commit SVN ==
  97  
  98  The constant for this event is `ArcanistEventType::TYPE_COMMIT_WILLCOMMITSVN`.
  99  
 100  This event is dispatched before an `svn commit` occurs and allows you to
 101  modify the commit message. Data available on this event:
 102  
 103    - `message` The text of the message.
 104  
 105  == Arcanist: Diff: Will Build Message ==
 106  
 107  The constant for this event is `ArcanistEventType::TYPE_DIFF_WILLBUILDMESSAGE`.
 108  
 109  This event is dispatched before an editable message is presented to the user,
 110  and allows you to, e.g., fill in default values for fields. Data available
 111  on this event:
 112  
 113    - `fields` A map of field values to be compiled into a message.
 114  
 115  == Arcanist: Diff: Was Created ==
 116  
 117  The constant for this event is `ArcanistEventType::TYPE_DIFF_WASCREATED`.
 118  
 119  This event is dispatched after a diff is created. It is currently only useful
 120  for collecting timing information. No data is available on this event.
 121  
 122  == Arcanist: Revision: Will Create Revision ==
 123  
 124  The constant for this event is
 125  `ArcanistEventType::TYPE_REVISION_WILLCREATEREVISION`.
 126  
 127  This event is dispatched before a revision is created. It allows you to modify
 128  fields to, e.g., edit revision titles. Data available on this event:
 129  
 130    - `specification` Parameters that will be used to invoke the
 131      `differential.createrevision` Conduit call.
 132  
 133  == Controller: Check Request ==
 134  
 135  The constant for this event is
 136  `PhabricatorEventType::TYPE_CONTROLLER_CHECKREQUEST`.
 137  
 138  This event is dispatched when controller is about to begin execution. It is
 139  meant for checking if the user is allowed to use the application at the moment.
 140  It can check if the user has performed too many operations recently, if his IP
 141  address is allowed or if the servers are overloaded to process the request.
 142  Data available on this event:
 143  
 144  - `request` Object of class @{class:AphrontRequest}.
 145  - `controller` Class name of the current controller.
 146  
 147  You can delegate the execution to another controller by modifying `controller`.
 148  
 149  == Maniphest: Will Edit Task ==
 150  
 151  The constant for this event is
 152  `PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK`.
 153  
 154  This event is dispatched before a task is edited, and allows you to respond to
 155  or alter the edit. Data available on this event:
 156  
 157    - ##task## The @{class:ManiphestTask} being edited.
 158    - ##transactions## The list of edits (objects of class
 159      @{class:ManiphestTransaction}) being applied.
 160    - ##new## A boolean indicating if this task is being created.
 161    - ##mail## If this edit originates from email, the
 162      @{class:PhabricatorMetaMTAReceivedMail} object.
 163  
 164  This is similar to the next event (did edit task) but occurs before the edit
 165  begins.
 166  
 167  == Maniphest: Did Edit Task ==
 168  
 169  The constant for this event is
 170  `PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK`.
 171  
 172  This event is dispatched after a task is edited, and allows you to react to the
 173  edit. Data available on this event:
 174  
 175    - ##task## The @{class:ManiphestTask} that was edited.
 176    - ##transactions## The list of edits (objects of class
 177      @{class:ManiphestTransaction}) that were applied.
 178    - ##new## A boolean indicating if this task was newly created.
 179    - ##mail## If this edit originates from email, the
 180      @{class:PhabricatorMetaMTAReceivedMail} object.
 181  
 182  This is similar to the previous event (will edit task) but occurs after the
 183  edit completes.
 184  
 185  == Differential: Will Mark Generated ==
 186  
 187  The constant for this event is
 188  `PhabricatorEventType::TYPE_DIFFERENTIAL_WILLMARKGENERATED`.
 189  
 190  This event is dispatched before Differential decides if a file is generated (and
 191  doesn't need to be reviewed) or not. Data available on this event:
 192  
 193    - ##corpus## Body of the file.
 194    - ##is_generated## Boolean indicating if this file should be treated as
 195      generated.
 196  
 197  == Diffusion: Did Discover Commit ==
 198  
 199  The constant for this event is
 200  `PhabricatorEventType::TYPE_DIFFUSION_DIDDISCOVERCOMMIT`.
 201  
 202  This event is dispatched when the daemons discover a commit for the first time.
 203  This event happens very early in the pipeline, and not all commit information
 204  will be available yet. Data available on this event:
 205  
 206    - `commit` The @{class:PhabricatorRepositoryCommit} that was discovered.
 207    - `repository` The @{class:PhabricatorRepository} the commit was discovered
 208      in.
 209  
 210  == Diffusion: Lookup User ==
 211  
 212  The constant for this event is
 213  `PhabricatorEventType::TYPE_DIFFUSION_LOOKUPUSER`.
 214  
 215  This event is dispatched when the daemons are trying to link a commit to a
 216  Phabricator user account. You can listen for it to improve the accuracy of
 217  associating users with their commits.
 218  
 219  By default, Phabricator will try to find matches based on usernames, real names,
 220  or email addresses, but this can result in incorrect matches (e.g., if you have
 221  several employees with the same name) or failures to match (e.g., if someone
 222  changed their email address). Listening for this event allows you to intercept
 223  the lookup and supplement the results from another datasource.
 224  
 225  Data available on this event:
 226  
 227    - `commit` The @{class:PhabricatorRepositoryCommit} that data is being looked
 228      up for.
 229    - `query` The author or committer string being looked up. This will usually
 230      be something like "Abraham Lincoln <[email protected]>", but
 231      comes from the commit metadata so it may not be well-formatted.
 232    - `result` The current result from the lookup (Phabricator's best guess at
 233      the user PHID of the user named in the "query"). To substitute the result
 234      with a different result, replace this with the correct PHID in your event
 235      listener.
 236  
 237  Using @{class@libphutil:PhutilEmailAddress} may be helpful in parsing the query.
 238  
 239  == Search: Did Update Index ==
 240  
 241  The constant for this event is
 242  `PhabricatorEventType::TYPE_SEARCH_DIDUPDATEINDEX`.
 243  
 244  This event is dispatched from the Search application's indexing engine, after
 245  it indexes a document. It allows you to publish search-like indexes into other
 246  systems.
 247  
 248  Note that this event happens after the update is fully complete: you can not
 249  prevent or modify the update. Further, the event may fire significantly later
 250  in real time than the update, as indexing may occur in the background. You
 251  should use other events if you need guarantees about when the event executes.
 252  
 253  Finally, this event may fire more than once for a single update. For example,
 254  if the search indexes are rebuilt, this event will fire on objects which have
 255  not actually changed.
 256  
 257  So, good use cases for event listeners are:
 258  
 259    - Updating secondary search indexes.
 260  
 261  Bad use cases are:
 262  
 263    - Editing the object or document.
 264    - Anything with side effects, like sending email.
 265  
 266  Data available on this event:
 267  
 268    - `phid` The PHID of the updated object.
 269    - `object` The object which was updated (like a @{class:ManiphesTask}).
 270    - `document` The @{class:PhabricatorSearchAbstractDocument} which was indexed.
 271      This contains an abstract representation of the object, and may be useful
 272      in populating secondary indexes because it provides a uniform API.
 273  
 274  == Test: Did Run Test ==
 275  
 276  The constant for this event is
 277  `PhabricatorEventType::TYPE_TEST_DIDRUNTEST`.
 278  
 279  This is a test event for testing event listeners. See above for details.
 280  
 281  == UI: Did Render Actions ==
 282  
 283  The constant for this event is
 284  `PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS`.
 285  
 286  This event is dispatched after a @{class:PhabricatorActionListView} is built by
 287  the UI. It allows you to add new actions that your application may provide, like
 288  "Fax this Object". Data available on this event:
 289  
 290    - `object` The object which actions are being rendered for.
 291    - `actions` The current list of available actions.
 292  
 293  NOTE: This event is unstable and subject to change.
 294  
 295  = Debugging Listeners =
 296  
 297  If you're having problems with your listener, try these steps:
 298  
 299    - If you're getting an error about Phabricator being unable to find the
 300      listener class, make sure you've added it to a libphutil library and
 301      configured Phabricator to load the library with `load-libraries`.
 302    - Make sure the listener is registered. It should appear in the "Events" tab
 303      of DarkConsole. If it's not there, you may have forgotten to add it to
 304      `events.listeners`.
 305    - Make sure it calls `listen()` on the right events in its `register()`
 306      method. If you don't listen for the events you're interested in, you
 307      won't get a callback.
 308    - Make sure the events you're listening for are actually happening. If they
 309      occur on a normal page they should appear in the "Events" tab of
 310      DarkConsole. If they occur on a POST, you could add a `phlog()`
 311      to the source code near the event and check your error log to make sure the
 312      code ran.
 313    - You can check if your callback is getting invoked by adding `phlog()` with
 314      a message and checking the error log.
 315    - You can try listening to `PhutilEventType::TYPE_ALL` instead of a specific
 316      event type to get all events, to narrow down whether problems are caused
 317      by the types of events you're listening to.
 318    - You can edit the `emit_test_event.php` script to emit other types of
 319      events instead, to test that your listener reacts to them properly. You
 320      might have to use fake data, but this gives you an easy way to test the
 321      at least the basics.
 322    - For scripts, you can run under `--trace` to see which events are emitted
 323      and how many handlers are listening to each event.
 324  
 325  = Next Steps =
 326  
 327  Continue by:
 328  
 329    - taking a look at @{class:PhabricatorExampleEventListener}; or
 330    - building a library with @{article:libphutil Libraries User Guide}.


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1