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

Begin modularizing Herald fields

Summary:
Ref T8726. This lays groundwork for modularizing Herald fields and modularizes the "Content source" field.

This doesn't touch conditions or values yet.

Test Plan: Created a rule with a "content source" field, created a new task, saw rule apply.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: eadler, joshuaspence, epriestley

Maniphest Tasks: T8726

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

+157 -19
+4
src/__phutil_library_map__.php
··· 934 934 'HeraldCommitAdapter' => 'applications/herald/adapter/HeraldCommitAdapter.php', 935 935 'HeraldCondition' => 'applications/herald/storage/HeraldCondition.php', 936 936 'HeraldConditionTranscript' => 'applications/herald/storage/transcript/HeraldConditionTranscript.php', 937 + 'HeraldContentSourceField' => 'applications/herald/field/HeraldContentSourceField.php', 937 938 'HeraldController' => 'applications/herald/controller/HeraldController.php', 938 939 'HeraldCustomAction' => 'applications/herald/extension/HeraldCustomAction.php', 939 940 'HeraldDAO' => 'applications/herald/storage/HeraldDAO.php', ··· 943 944 'HeraldDisableController' => 'applications/herald/controller/HeraldDisableController.php', 944 945 'HeraldEffect' => 'applications/herald/engine/HeraldEffect.php', 945 946 'HeraldEngine' => 'applications/herald/engine/HeraldEngine.php', 947 + 'HeraldField' => 'applications/herald/field/HeraldField.php', 946 948 'HeraldInvalidActionException' => 'applications/herald/engine/exception/HeraldInvalidActionException.php', 947 949 'HeraldInvalidConditionException' => 'applications/herald/engine/exception/HeraldInvalidConditionException.php', 948 950 'HeraldManageGlobalRulesCapability' => 'applications/herald/capability/HeraldManageGlobalRulesCapability.php', ··· 4429 4431 'HeraldCommitAdapter' => 'HeraldAdapter', 4430 4432 'HeraldCondition' => 'HeraldDAO', 4431 4433 'HeraldConditionTranscript' => 'Phobject', 4434 + 'HeraldContentSourceField' => 'HeraldField', 4432 4435 'HeraldController' => 'PhabricatorController', 4433 4436 'HeraldCustomAction' => 'Phobject', 4434 4437 'HeraldDAO' => 'PhabricatorLiskDAO', ··· 4438 4441 'HeraldDisableController' => 'HeraldController', 4439 4442 'HeraldEffect' => 'Phobject', 4440 4443 'HeraldEngine' => 'Phobject', 4444 + 'HeraldField' => 'Phobject', 4441 4445 'HeraldInvalidActionException' => 'Exception', 4442 4446 'HeraldInvalidConditionException' => 'Exception', 4443 4447 'HeraldManageGlobalRulesCapability' => 'PhabricatorPolicyCapability',
+63 -18
src/applications/herald/adapter/HeraldAdapter.php
··· 24 24 const FIELD_RULE = 'rule'; 25 25 const FIELD_AFFECTED_PACKAGE = 'affected-package'; 26 26 const FIELD_AFFECTED_PACKAGE_OWNER = 'affected-package-owner'; 27 - const FIELD_CONTENT_SOURCE = 'contentsource'; 28 27 const FIELD_ALWAYS = 'always'; 29 28 const FIELD_AUTHOR_PROJECTS = 'authorprojects'; 30 29 const FIELD_PROJECTS = 'projects'; ··· 113 112 private $emailPHIDs = array(); 114 113 private $forcedEmailPHIDs = array(); 115 114 private $unsubscribedPHIDs; 115 + private $fieldMap; 116 116 117 117 public function getEmailPHIDs() { 118 118 return array_values($this->emailPHIDs); ··· 190 190 abstract public function getHeraldName(); 191 191 192 192 public function getHeraldField($field_name) { 193 + $impl = $this->getFieldImplementation($field_name); 194 + if ($impl) { 195 + return $impl->getHeraldFieldValue($this->getObject()); 196 + } 197 + 193 198 switch ($field_name) { 194 199 case self::FIELD_RULE: 195 200 return null; 196 - case self::FIELD_CONTENT_SOURCE: 197 - return $this->getContentSource()->getSource(); 198 201 case self::FIELD_ALWAYS: 199 202 return true; 200 203 case self::FIELD_IS_NEW_OBJECT: ··· 354 357 355 358 /* -( Fields )------------------------------------------------------------- */ 356 359 360 + private function getFieldImplementationMap() { 361 + if ($this->fieldMap === null) { 362 + // We can't use PhutilClassMapQuery here because field expansion 363 + // depends on the adapter and object. 364 + 365 + $object = $this->getObject(); 366 + 367 + $map = array(); 368 + $all = HeraldField::getAllFields(); 369 + foreach ($all as $key => $field) { 370 + if (!$field->supportsObject($object)) { 371 + continue; 372 + } 373 + $subfields = $field->getFieldsForObject($object); 374 + foreach ($subfields as $subkey => $subfield) { 375 + if (isset($map[$subkey])) { 376 + throw new Exception( 377 + pht( 378 + 'Two HeraldFields (of classes "%s" and "%s") have the same '. 379 + 'field key ("%s") after expansion for an object of class '. 380 + '"%s" inside adapter "%s". Each field must have a unique '. 381 + 'field key.', 382 + get_class($subfield), 383 + get_class($map[$subkey]), 384 + $subkey, 385 + get_class($object), 386 + get_class($this))); 387 + } 388 + 389 + $subfield = id(clone $subfield)->setAdapter($this); 390 + 391 + $map[$subkey] = $subfield; 392 + } 393 + } 394 + $this->fieldMap = $map; 395 + } 396 + 397 + return $this->fieldMap; 398 + } 399 + 400 + private function getFieldImplementation($key) { 401 + return idx($this->getFieldImplementationMap(), $key); 402 + } 357 403 358 404 public function getFields() { 359 - $fields = array(); 405 + $fields = array_keys($this->getFieldImplementationMap()); 360 406 361 407 $fields[] = self::FIELD_ALWAYS; 362 408 $fields[] = self::FIELD_RULE; ··· 373 419 } 374 420 375 421 public function getFieldNameMap() { 376 - return array( 422 + $map = mpull($this->getFieldImplementationMap(), 'getHeraldFieldName'); 423 + 424 + return $map + array( 377 425 self::FIELD_TITLE => pht('Title'), 378 426 self::FIELD_BODY => pht('Body'), 379 427 self::FIELD_AUTHOR => pht('Author'), ··· 394 442 self::FIELD_AFFECTED_PACKAGE => pht('Any affected package'), 395 443 self::FIELD_AFFECTED_PACKAGE_OWNER => 396 444 pht("Any affected package's owner"), 397 - self::FIELD_CONTENT_SOURCE => pht('Content Source'), 398 445 self::FIELD_ALWAYS => pht('Always'), 399 446 self::FIELD_AUTHOR_PROJECTS => pht("Author's projects"), 400 447 self::FIELD_PROJECTS => pht('Projects'), ··· 452 499 } 453 500 454 501 public function getConditionsForField($field) { 502 + $impl = $this->getFieldImplementation($field); 503 + if ($impl) { 504 + return $impl->getHeraldFieldConditions(); 505 + } 506 + 455 507 switch ($field) { 456 508 case self::FIELD_TITLE: 457 509 case self::FIELD_BODY: ··· 525 577 return array( 526 578 self::CONDITION_RULE, 527 579 self::CONDITION_NOT_RULE, 528 - ); 529 - case self::FIELD_CONTENT_SOURCE: 530 - return array( 531 - self::CONDITION_IS, 532 - self::CONDITION_IS_NOT, 533 580 ); 534 581 case self::FIELD_ALWAYS: 535 582 return array( ··· 940 987 941 988 942 989 public function getValueTypeForFieldAndCondition($field, $condition) { 990 + $impl = $this->getFieldImplementation($field); 991 + if ($impl) { 992 + return $impl->getHeraldFieldValueType($condition); 993 + } 943 994 944 995 if ($this->isHeraldCustomKey($field)) { 945 996 $value_type = $this->getCustomFieldValueTypeForFieldAndCondition( ··· 958 1009 return self::VALUE_TEXT; 959 1010 case self::CONDITION_IS: 960 1011 case self::CONDITION_IS_NOT: 961 - switch ($field) { 962 - case self::FIELD_CONTENT_SOURCE: 963 - return self::VALUE_CONTENT_SOURCE; 964 - default: 965 - return self::VALUE_TEXT; 966 - } 967 - break; 1012 + return self::VALUE_TEXT; 968 1013 case self::CONDITION_IS_ANY: 969 1014 case self::CONDITION_IS_NOT_ANY: 970 1015 switch ($field) {
-1
src/applications/herald/adapter/HeraldManiphestTaskAdapter.php
··· 67 67 self::FIELD_AUTHOR, 68 68 self::FIELD_ASSIGNEE, 69 69 self::FIELD_CC, 70 - self::FIELD_CONTENT_SOURCE, 71 70 self::FIELD_PROJECTS, 72 71 self::FIELD_TASK_PRIORITY, 73 72 self::FIELD_TASK_STATUS,
+30
src/applications/herald/field/HeraldContentSourceField.php
··· 1 + <?php 2 + 3 + final class HeraldContentSourceField extends HeraldField { 4 + 5 + const FIELDCONST = 'contentsource'; 6 + 7 + public function getHeraldFieldName() { 8 + return pht('Content source'); 9 + } 10 + 11 + public function getHeraldFieldValue($object) { 12 + return $this->getAdapter()->getContentSource()->getSource(); 13 + } 14 + 15 + public function getHeraldFieldConditions() { 16 + return array( 17 + HeraldAdapter::CONDITION_IS, 18 + HeraldAdapter::CONDITION_IS_NOT, 19 + ); 20 + } 21 + 22 + public function getHeraldFieldValueType($condition) { 23 + return HeraldAdapter::VALUE_CONTENT_SOURCE; 24 + } 25 + 26 + public function supportsObject($object) { 27 + return true; 28 + } 29 + 30 + }
+60
src/applications/herald/field/HeraldField.php
··· 1 + <?php 2 + 3 + abstract class HeraldField extends Phobject { 4 + 5 + private $adapter; 6 + 7 + abstract public function getHeraldFieldName(); 8 + abstract public function getHeraldFieldValue($object); 9 + abstract public function getHeraldFieldConditions(); 10 + abstract public function getHeraldFieldValueType($condition); 11 + 12 + abstract public function supportsObject($object); 13 + 14 + public function getFieldsForObject($object) { 15 + return array($this->getFieldConstant() => $this); 16 + } 17 + 18 + final public function setAdapter(HeraldAdapter $adapter) { 19 + $this->adapter = $adapter; 20 + return $this; 21 + } 22 + 23 + final public function getAdapter() { 24 + return $this->adapter; 25 + } 26 + 27 + final public function getFieldConstant() { 28 + $class = new ReflectionClass($this); 29 + 30 + $const = $class->getConstant('FIELDCONST'); 31 + if ($const === false) { 32 + throw new Exception( 33 + pht( 34 + '"%s" class "%s" must define a "%s" property.', 35 + __CLASS__, 36 + get_class($this), 37 + 'FIELDCONST')); 38 + } 39 + 40 + if (!is_string($const) || (strlen($const) > 32)) { 41 + throw new Exception( 42 + pht( 43 + '"%s" class "%s" has an invalid "%s" property. Field constants '. 44 + 'must be strings and no more than 32 bytes in length.', 45 + __CLASS__, 46 + get_class($this), 47 + 'FIELDCONST')); 48 + } 49 + 50 + return $const; 51 + } 52 + 53 + final public static function getAllFields() { 54 + return id(new PhutilClassMapQuery()) 55 + ->setAncestorClass(__CLASS__) 56 + ->setUniqueMethod('getFieldConstant') 57 + ->execute(); 58 + } 59 + 60 + }