[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |