[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/base/ -> PhabricatorApplication.php (source)

   1  <?php
   2  
   3  /**
   4   * @task  info  Application Information
   5   * @task  ui    UI Integration
   6   * @task  uri   URI Routing
   7   * @task  fact  Fact Integration
   8   * @task  meta  Application Management
   9   */
  10  abstract class PhabricatorApplication implements PhabricatorPolicyInterface {
  11  
  12    const GROUP_CORE            = 'core';
  13    const GROUP_UTILITIES       = 'util';
  14    const GROUP_ADMIN           = 'admin';
  15    const GROUP_DEVELOPER       = 'developer';
  16  
  17    public static function getApplicationGroups() {
  18      return array(
  19        self::GROUP_CORE          => pht('Core Applications'),
  20        self::GROUP_UTILITIES     => pht('Utilities'),
  21        self::GROUP_ADMIN         => pht('Administration'),
  22        self::GROUP_DEVELOPER     => pht('Developer Tools'),
  23      );
  24    }
  25  
  26  
  27  /* -(  Application Information  )-------------------------------------------- */
  28  
  29  
  30    /**
  31     * TODO: This should be abstract, but is not for historical reasons.
  32     */
  33    public function getName() {
  34      phutil_deprecated(
  35        'Automatic naming of `PhabricatorApplication` classes.',
  36        'You should override the `getName` method.');
  37  
  38      $match = null;
  39      $regex = '/^PhabricatorApplication([A-Z][a-zA-Z]*)$/';
  40      if (preg_match($regex, get_class($this), $match)) {
  41        return $match[1];
  42      }
  43  
  44      throw new PhutilMethodNotImplementedException();
  45    }
  46  
  47    public function getShortDescription() {
  48      return $this->getName().' Application';
  49    }
  50  
  51    public function isInstalled() {
  52      if (!$this->canUninstall()) {
  53        return true;
  54      }
  55  
  56      $prototypes = PhabricatorEnv::getEnvConfig('phabricator.show-prototypes');
  57      if (!$prototypes && $this->isPrototype()) {
  58        return false;
  59      }
  60  
  61      $uninstalled = PhabricatorEnv::getEnvConfig(
  62        'phabricator.uninstalled-applications');
  63  
  64      return empty($uninstalled[get_class($this)]);
  65    }
  66  
  67  
  68    public function isPrototype() {
  69      return false;
  70    }
  71  
  72  
  73    /**
  74     * Return `true` if this application should never appear in application lists
  75     * in the UI. Primarily intended for unit test applications or other
  76     * pseudo-applications.
  77     *
  78     * Few applications should be unlisted. For most applications, use
  79     * @{method:isLaunchable} to hide them from main launch views instead.
  80     *
  81     * @return bool True to remove application from UI lists.
  82     */
  83    public function isUnlisted() {
  84      return false;
  85    }
  86  
  87  
  88    /**
  89     * Return `true` if this application is a normal application with a base
  90     * URI and a web interface.
  91     *
  92     * Launchable applications can be pinned to the home page, and show up in the
  93     * "Launcher" view of the Applications application. Making an application
  94     * unlauncahble prevents pinning and hides it from this view.
  95     *
  96     * Usually, an application should be marked unlaunchable if:
  97     *
  98     *   - it is available on every page anyway (like search); or
  99     *   - it does not have a web interface (like subscriptions); or
 100     *   - it is still pre-release and being intentionally buried.
 101     *
 102     * To hide applications more completely, use @{method:isUnlisted}.
 103     *
 104     * @return bool True if the application is launchable.
 105     */
 106    public function isLaunchable() {
 107      return true;
 108    }
 109  
 110  
 111    /**
 112     * Return `true` if this application should be pinned by default.
 113     *
 114     * Users who have not yet set preferences see a default list of applications.
 115     *
 116     * @param PhabricatorUser User viewing the pinned application list.
 117     * @return bool True if this application should be pinned by default.
 118     */
 119    public function isPinnedByDefault(PhabricatorUser $viewer) {
 120      return false;
 121    }
 122  
 123  
 124    /**
 125     * Returns true if an application is first-party (developed by Phacility)
 126     * and false otherwise.
 127     *
 128     * @return bool True if this application is developed by Phacility.
 129     */
 130    final public function isFirstParty() {
 131      $where = id(new ReflectionClass($this))->getFileName();
 132      $root = phutil_get_library_root('phabricator');
 133  
 134      if (!Filesystem::isDescendant($where, $root)) {
 135        return false;
 136      }
 137  
 138      if (Filesystem::isDescendant($where, $root.'/extensions')) {
 139        return false;
 140      }
 141  
 142      return true;
 143    }
 144  
 145    public function canUninstall() {
 146      return true;
 147    }
 148  
 149    public function getPHID() {
 150      return 'PHID-APPS-'.get_class($this);
 151    }
 152  
 153    public function getTypeaheadURI() {
 154      return $this->isLaunchable() ? $this->getBaseURI() : null;
 155    }
 156  
 157    public function getBaseURI() {
 158      return null;
 159    }
 160  
 161    public function getApplicationURI($path = '') {
 162      return $this->getBaseURI().ltrim($path, '/');
 163    }
 164  
 165    public function getIconURI() {
 166      return null;
 167    }
 168  
 169    public function getIconName() {
 170      return 'application';
 171    }
 172  
 173    public function getApplicationOrder() {
 174      return PHP_INT_MAX;
 175    }
 176  
 177    public function getApplicationGroup() {
 178      return self::GROUP_CORE;
 179    }
 180  
 181    public function getTitleGlyph() {
 182      return null;
 183    }
 184  
 185    public function getHelpURI() {
 186      return null;
 187    }
 188  
 189    public function getOverview() {
 190      return null;
 191    }
 192  
 193    public function getEventListeners() {
 194      return array();
 195    }
 196  
 197    public function getRemarkupRules() {
 198      return array();
 199    }
 200  
 201  
 202  /* -(  URI Routing  )-------------------------------------------------------- */
 203  
 204  
 205    public function getRoutes() {
 206      return array();
 207    }
 208  
 209  
 210  /* -(  Fact Integration  )--------------------------------------------------- */
 211  
 212  
 213    public function getFactObjectsForAnalysis() {
 214      return array();
 215    }
 216  
 217  
 218  /* -(  UI Integration  )----------------------------------------------------- */
 219  
 220  
 221    /**
 222     * Render status elements (like "3 Waiting Reviews") for application list
 223     * views. These provide a way to alert users to new or pending action items
 224     * in applications.
 225     *
 226     * @param PhabricatorUser Viewing user.
 227     * @return list<PhabricatorApplicationStatusView> Application status elements.
 228     * @task ui
 229     */
 230    public function loadStatus(PhabricatorUser $user) {
 231      return array();
 232    }
 233  
 234  
 235    /**
 236     * You can provide an optional piece of flavor text for the application. This
 237     * is currently rendered in application launch views if the application has no
 238     * status elements.
 239     *
 240     * @return string|null Flavor text.
 241     * @task ui
 242     */
 243    public function getFlavorText() {
 244      return null;
 245    }
 246  
 247  
 248    /**
 249     * Build items for the main menu.
 250     *
 251     * @param  PhabricatorUser    The viewing user.
 252     * @param  AphrontController  The current controller. May be null for special
 253     *                            pages like 404, exception handlers, etc.
 254     * @return list<PHUIListItemView> List of menu items.
 255     * @task ui
 256     */
 257    public function buildMainMenuItems(
 258      PhabricatorUser $user,
 259      PhabricatorController $controller = null) {
 260      return array();
 261    }
 262  
 263  
 264    /**
 265     * Build extra items for the main menu. Generally, this is used to render
 266     * static dropdowns.
 267     *
 268     * @param  PhabricatorUser    The viewing user.
 269     * @param  AphrontController  The current controller. May be null for special
 270     *                            pages like 404, exception handlers, etc.
 271     * @return view               List of menu items.
 272     * @task ui
 273     */
 274    public function buildMainMenuExtraNodes(
 275      PhabricatorUser $viewer,
 276      PhabricatorController $controller = null) {
 277      return array();
 278    }
 279  
 280  
 281    /**
 282     * Build items for the "quick create" menu.
 283     *
 284     * @param   PhabricatorUser         The viewing user.
 285     * @return  list<PHUIListItemView>  List of menu items.
 286     */
 287    public function getQuickCreateItems(PhabricatorUser $viewer) {
 288      return array();
 289    }
 290  
 291  
 292  /* -(  Application Management  )--------------------------------------------- */
 293  
 294  
 295    public static function getByClass($class_name) {
 296      $selected = null;
 297      $applications = PhabricatorApplication::getAllApplications();
 298  
 299      foreach ($applications as $application) {
 300        if (get_class($application) == $class_name) {
 301          $selected = $application;
 302          break;
 303        }
 304      }
 305  
 306      if (!$selected) {
 307        throw new Exception("No application '{$class_name}'!");
 308      }
 309  
 310      return $selected;
 311    }
 312  
 313    public static function getAllApplications() {
 314      static $applications;
 315  
 316      if ($applications === null) {
 317        $apps = id(new PhutilSymbolLoader())
 318          ->setAncestorClass(__CLASS__)
 319          ->loadObjects();
 320  
 321        // Reorder the applications into "application order". Notably, this
 322        // ensures their event handlers register in application order.
 323        $apps = msort($apps, 'getApplicationOrder');
 324        $apps = mgroup($apps, 'getApplicationGroup');
 325  
 326        $group_order = array_keys(self::getApplicationGroups());
 327        $apps = array_select_keys($apps, $group_order) + $apps;
 328  
 329        $apps = array_mergev($apps);
 330  
 331        $applications = $apps;
 332      }
 333  
 334      return $applications;
 335    }
 336  
 337    public static function getAllInstalledApplications() {
 338      $all_applications = self::getAllApplications();
 339      $apps = array();
 340      foreach ($all_applications as $app) {
 341        if (!$app->isInstalled()) {
 342          continue;
 343        }
 344  
 345        $apps[] = $app;
 346      }
 347  
 348      return $apps;
 349    }
 350  
 351  
 352    /**
 353     * Determine if an application is installed, by application class name.
 354     *
 355     * To check if an application is installed //and// available to a particular
 356     * viewer, user @{method:isClassInstalledForViewer}.
 357     *
 358     * @param string  Application class name.
 359     * @return bool   True if the class is installed.
 360     * @task meta
 361     */
 362    public static function isClassInstalled($class) {
 363      return self::getByClass($class)->isInstalled();
 364    }
 365  
 366  
 367    /**
 368     * Determine if an application is installed and available to a viewer, by
 369     * application class name.
 370     *
 371     * To check if an application is installed at all, use
 372     * @{method:isClassInstalled}.
 373     *
 374     * @param string Application class name.
 375     * @param PhabricatorUser Viewing user.
 376     * @return bool True if the class is installed for the viewer.
 377     * @task meta
 378     */
 379    public static function isClassInstalledForViewer(
 380      $class,
 381      PhabricatorUser $viewer) {
 382  
 383      if (!self::isClassInstalled($class)) {
 384        return false;
 385      }
 386  
 387      return PhabricatorPolicyFilter::hasCapability(
 388        $viewer,
 389        self::getByClass($class),
 390        PhabricatorPolicyCapability::CAN_VIEW);
 391    }
 392  
 393  
 394  /* -(  PhabricatorPolicyInterface  )----------------------------------------- */
 395  
 396  
 397    public function getCapabilities() {
 398      return array_merge(
 399        array(
 400          PhabricatorPolicyCapability::CAN_VIEW,
 401          PhabricatorPolicyCapability::CAN_EDIT,
 402        ),
 403        array_keys($this->getCustomCapabilities()));
 404    }
 405  
 406    public function getPolicy($capability) {
 407      $default = $this->getCustomPolicySetting($capability);
 408      if ($default) {
 409        return $default;
 410      }
 411  
 412      switch ($capability) {
 413        case PhabricatorPolicyCapability::CAN_VIEW:
 414          return PhabricatorPolicies::getMostOpenPolicy();
 415        case PhabricatorPolicyCapability::CAN_EDIT:
 416          return PhabricatorPolicies::POLICY_ADMIN;
 417        default:
 418          $spec = $this->getCustomCapabilitySpecification($capability);
 419          return idx($spec, 'default', PhabricatorPolicies::POLICY_USER);
 420      }
 421    }
 422  
 423    public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
 424      return false;
 425    }
 426  
 427    public function describeAutomaticCapability($capability) {
 428      return null;
 429    }
 430  
 431  
 432  /* -(  Policies  )----------------------------------------------------------- */
 433  
 434    protected function getCustomCapabilities() {
 435      return array();
 436    }
 437  
 438    private function getCustomPolicySetting($capability) {
 439      if (!$this->isCapabilityEditable($capability)) {
 440        return null;
 441      }
 442  
 443      $config = PhabricatorEnv::getEnvConfig('phabricator.application-settings');
 444  
 445      $app = idx($config, $this->getPHID());
 446      if (!$app) {
 447        return null;
 448      }
 449  
 450      $policy = idx($app, 'policy');
 451      if (!$policy) {
 452        return null;
 453      }
 454  
 455      return idx($policy, $capability);
 456    }
 457  
 458  
 459    private function getCustomCapabilitySpecification($capability) {
 460      $custom = $this->getCustomCapabilities();
 461      if (!isset($custom[$capability])) {
 462        throw new Exception("Unknown capability '{$capability}'!");
 463      }
 464      return $custom[$capability];
 465    }
 466  
 467    public function getCapabilityLabel($capability) {
 468      switch ($capability) {
 469        case PhabricatorPolicyCapability::CAN_VIEW:
 470          return pht('Can Use Application');
 471        case PhabricatorPolicyCapability::CAN_EDIT:
 472          return pht('Can Configure Application');
 473      }
 474  
 475      $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability);
 476      if ($capobj) {
 477        return $capobj->getCapabilityName();
 478      }
 479  
 480      return null;
 481    }
 482  
 483    public function isCapabilityEditable($capability) {
 484      switch ($capability) {
 485        case PhabricatorPolicyCapability::CAN_VIEW:
 486          return $this->canUninstall();
 487        case PhabricatorPolicyCapability::CAN_EDIT:
 488          return false;
 489        default:
 490          $spec = $this->getCustomCapabilitySpecification($capability);
 491          return idx($spec, 'edit', true);
 492      }
 493    }
 494  
 495    public function getCapabilityCaption($capability) {
 496      switch ($capability) {
 497        case PhabricatorPolicyCapability::CAN_VIEW:
 498          if (!$this->canUninstall()) {
 499            return pht(
 500              'This application is required for Phabricator to operate, so all '.
 501              'users must have access to it.');
 502          } else {
 503            return null;
 504          }
 505        case PhabricatorPolicyCapability::CAN_EDIT:
 506          return null;
 507        default:
 508          $spec = $this->getCustomCapabilitySpecification($capability);
 509          return idx($spec, 'caption');
 510      }
 511    }
 512  
 513  }


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