Phabricator Code LayoutPhabricator Contributor Documentation (Developer Guides)
Guide to Phabricator code layout, including how URI mapping works through application class and subdirectory organization best practices.
When a user visits a Phabricator URI, the Phabricator infrastructure parses that URI with a regular expression to determine what controller class to load.
The Phabricator infrastructure knows where a given controller class lives on disk from a cache file the Arcanist phutil mapper generates. This mapping should be updated whenever new classes or files are added:
arc liberate /path/to/phabricator/src
Finally, a given controller class will map to an application which will have most of its code in standardized subdirectories and classes.
Suppose you were working on the application Derp.
If Derp were as simple as possible, it would have one subdirectory:
containing the file DerpController.php with the class
- DerpController: minimally implements a processRequest() method which returns some AphrontResponse object. The class would probably extend PhabricatorController.
If Derp were (relatively) complex, one could reasonably expect to see the following directory layout:
phabricator/src/applications/derp/conduit/ phabricator/src/applications/derp/constants/ phabricator/src/applications/derp/controller/ phabricator/src/applications/derp/editor/ phabricator/src/applications/derp/exception/ phabricator/src/applications/derp/query/ phabricator/src/applications/derp/replyhandler/ phabricator/src/applications/derp/storage/ phabricator/src/applications/derp/view/
These directories under phabricator/src/applications/derp/ represent the basic set of class types from which most Phabricator applications are assembled. Each would contain a class file. For Derp, these classes could be something like:
- DerpConstants: constants used in the Derp application.
- DerpController: business logic providing functionality for a given URI. Typically, controllers load data via Storage or Query classes, then present the data to the user via one or more View classes.
- DerpEditor: business logic for workflows that change one or more Storage objects. Editor classes are only necessary for particularly complicated edits and should be used pragmatically versus Storage objects.
- DerpException: exceptions used in the Derp application.
- DerpQuery: query one or more storage objects for pertinent Derp application data. PhabricatorOffsetPagedQuery is particularly handy for pagination and works well with AphrontPagerView.
- DerpReplyHandler: business logic from any configured email interactions users can have with the Derp application.
- DerpStorage: storage objects for the Derp application. Typically there is a base class which extends PhabricatorLiskDAO to configure application-wide storage settings like the application (thus database) name. Reading more about the LiskDAO is highly recommended.
- DerpView: view objects for the Derp application. Typically these extend AphrontView.
- DerpConduitAPIMethod: provides any and all Derp application functionality that is accessible over Conduit.
However, it is likely that Derp is even more complex, and rather than containing one class, each directory has several classes. A typical example happens around the CRUD of an object:
- DerpBaseController: typically extends PhabricatorController and contains any controller-specific functionality used throughout the Derp application.
- DerpDeleteController: typically extends DerpBaseController and presents a confirmation dialogue to the user about deleting a Derp.
- DerpEditController: typically extends DerpBaseController and presents a form to create and edit Derps. Most likely uses AphrontFormView and various AphrontFormXControl classes such as AphrontFormTextControl to create the form.
- DerpListController: typically extends DerpBaseController and displays a set of one or more Derps. Might use AphrontTableView to create a table of Derps.
- DerpViewController: typically extends DerpBaseController and displays a single Derp.
Some especially awesome directories might have a __tests__ subdirectory containing all pertinent unit test code for the class.