1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-19 05:12:41 +01:00

Modularize application extensions to EditEngine

Summary:
Ref T9132. Currently, EditEngine had some branchy-`instanceof` code like this:

```
if ($object instanceof Whatever) {
  do_magic();
}

if ($object instanceof SomethingElse) {
  do_other_magic();
}
```

...where `Whatever` and `SomethingElse` are first-party applications like ProjectsInterface and SubscribersInterface.

This kind of code is generally bad because third-parties can't add new stuff, and it suggest something is kind of hacky in its architecture. Ideally, we would eventually get rid of almost all of this.

T9789 is a similar discussion of this for the next layer down (`TransactionEditor`) and plans to get rid of branchy-instanceofs there too.

Since I'm about to add more stuff here (for Custom Fields), split it out first so I'm not digging us any deeper than I already dug us.

Broadly, this allows third-party extensions to add fields to every EditEngine UI if they want, like we do for Policies, Subscribers, Projects and Comments today (and CustomFields soon).

Test Plan:
{F1007575}

  - Observed that all fields still appear on the form and seem to work correctly.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9132

Differential Revision: https://secure.phabricator.com/D14599
This commit is contained in:
epriestley 2015-11-29 10:05:41 -08:00
parent 9a19309345
commit acd955c6c9
10 changed files with 477 additions and 146 deletions

View file

@ -1844,6 +1844,7 @@ phutil_register_library_map(array(
'PhabricatorChatLogQuery' => 'applications/chatlog/query/PhabricatorChatLogQuery.php',
'PhabricatorChunkedFileStorageEngine' => 'applications/files/engine/PhabricatorChunkedFileStorageEngine.php',
'PhabricatorClusterConfigOptions' => 'applications/config/option/PhabricatorClusterConfigOptions.php',
'PhabricatorCommentEditEngineExtension' => 'applications/transactions/editengineextension/PhabricatorCommentEditEngineExtension.php',
'PhabricatorCommentEditField' => 'applications/transactions/editfield/PhabricatorCommentEditField.php',
'PhabricatorCommentEditType' => 'applications/transactions/edittype/PhabricatorCommentEditType.php',
'PhabricatorCommitBranchesField' => 'applications/repository/customfield/PhabricatorCommitBranchesField.php',
@ -2132,6 +2133,8 @@ phutil_register_library_map(array(
'PhabricatorEditEngineConfigurationTransactionQuery' => 'applications/transactions/query/PhabricatorEditEngineConfigurationTransactionQuery.php',
'PhabricatorEditEngineConfigurationViewController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php',
'PhabricatorEditEngineController' => 'applications/transactions/controller/PhabricatorEditEngineController.php',
'PhabricatorEditEngineExtension' => 'applications/transactions/editengineextension/PhabricatorEditEngineExtension.php',
'PhabricatorEditEngineExtensionModule' => 'applications/transactions/editengineextension/PhabricatorEditEngineExtensionModule.php',
'PhabricatorEditEngineListController' => 'applications/transactions/controller/PhabricatorEditEngineListController.php',
'PhabricatorEditEngineQuery' => 'applications/transactions/query/PhabricatorEditEngineQuery.php',
'PhabricatorEditEngineSearchEngine' => 'applications/transactions/query/PhabricatorEditEngineSearchEngine.php',
@ -2706,6 +2709,7 @@ phutil_register_library_map(array(
'PhabricatorPolicyDAO' => 'applications/policy/storage/PhabricatorPolicyDAO.php',
'PhabricatorPolicyDataTestCase' => 'applications/policy/__tests__/PhabricatorPolicyDataTestCase.php',
'PhabricatorPolicyEditController' => 'applications/policy/controller/PhabricatorPolicyEditController.php',
'PhabricatorPolicyEditEngineExtension' => 'applications/policy/editor/PhabricatorPolicyEditEngineExtension.php',
'PhabricatorPolicyEditField' => 'applications/transactions/editfield/PhabricatorPolicyEditField.php',
'PhabricatorPolicyException' => 'applications/policy/exception/PhabricatorPolicyException.php',
'PhabricatorPolicyExplainController' => 'applications/policy/controller/PhabricatorPolicyExplainController.php',
@ -2797,6 +2801,7 @@ phutil_register_library_map(array(
'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php',
'PhabricatorProjectViewController' => 'applications/project/controller/PhabricatorProjectViewController.php',
'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php',
'PhabricatorProjectsEditEngineExtension' => 'applications/project/editor/PhabricatorProjectsEditEngineExtension.php',
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
'PhabricatorProjectsPolicyRule' => 'applications/project/policyrule/PhabricatorProjectsPolicyRule.php',
'PhabricatorProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorProtocolAdapter.php',
@ -3087,6 +3092,7 @@ phutil_register_library_map(array(
'PhabricatorSubscriptionsAddSubscribersHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsAddSubscribersHeraldAction.php',
'PhabricatorSubscriptionsApplication' => 'applications/subscriptions/application/PhabricatorSubscriptionsApplication.php',
'PhabricatorSubscriptionsEditController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php',
'PhabricatorSubscriptionsEditEngineExtension' => 'applications/subscriptions/editor/PhabricatorSubscriptionsEditEngineExtension.php',
'PhabricatorSubscriptionsEditor' => 'applications/subscriptions/editor/PhabricatorSubscriptionsEditor.php',
'PhabricatorSubscriptionsHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsHeraldAction.php',
'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php',
@ -5896,6 +5902,7 @@ phutil_register_library_map(array(
'PhabricatorChatLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorChunkedFileStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorClusterConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorCommentEditEngineExtension' => 'PhabricatorEditEngineExtension',
'PhabricatorCommentEditField' => 'PhabricatorEditField',
'PhabricatorCommentEditType' => 'PhabricatorEditType',
'PhabricatorCommitBranchesField' => 'PhabricatorCommitCustomField',
@ -6232,6 +6239,8 @@ phutil_register_library_map(array(
'PhabricatorEditEngineConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorEditEngineConfigurationViewController' => 'PhabricatorEditEngineController',
'PhabricatorEditEngineController' => 'PhabricatorApplicationTransactionController',
'PhabricatorEditEngineExtension' => 'Phobject',
'PhabricatorEditEngineExtensionModule' => 'PhabricatorConfigModule',
'PhabricatorEditEngineListController' => 'PhabricatorEditEngineController',
'PhabricatorEditEngineQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorEditEngineSearchEngine' => 'PhabricatorApplicationSearchEngine',
@ -6898,6 +6907,7 @@ phutil_register_library_map(array(
'PhabricatorPolicyDAO' => 'PhabricatorLiskDAO',
'PhabricatorPolicyDataTestCase' => 'PhabricatorTestCase',
'PhabricatorPolicyEditController' => 'PhabricatorPolicyController',
'PhabricatorPolicyEditEngineExtension' => 'PhabricatorEditEngineExtension',
'PhabricatorPolicyEditField' => 'PhabricatorEditField',
'PhabricatorPolicyException' => 'Exception',
'PhabricatorPolicyExplainController' => 'PhabricatorPolicyController',
@ -7014,6 +7024,7 @@ phutil_register_library_map(array(
'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorProjectViewController' => 'PhabricatorProjectController',
'PhabricatorProjectWatchController' => 'PhabricatorProjectController',
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
'PhabricatorProjectsPolicyRule' => 'PhabricatorPolicyRule',
'PhabricatorProtocolAdapter' => 'Phobject',
@ -7360,6 +7371,7 @@ phutil_register_library_map(array(
'PhabricatorSubscriptionsAddSubscribersHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
'PhabricatorSubscriptionsApplication' => 'PhabricatorApplication',
'PhabricatorSubscriptionsEditController' => 'PhabricatorController',
'PhabricatorSubscriptionsEditEngineExtension' => 'PhabricatorEditEngineExtension',
'PhabricatorSubscriptionsEditor' => 'PhabricatorEditor',
'PhabricatorSubscriptionsHeraldAction' => 'HeraldAction',
'PhabricatorSubscriptionsListController' => 'PhabricatorController',

View file

@ -0,0 +1,118 @@
<?php
final class PhabricatorPolicyEditEngineExtension
extends PhabricatorEditEngineExtension {
const EXTENSIONKEY = 'policy.policy';
public function getExtensionPriority() {
return 250;
}
public function isExtensionEnabled() {
return true;
}
public function getExtensionName() {
return pht('Policies');
}
public function supportsObject(
PhabricatorEditEngine $engine,
PhabricatorApplicationTransactionInterface $object) {
return ($object instanceof PhabricatorPolicyInterface);
}
public function buildCustomEditFields(
PhabricatorEditEngine $engine,
PhabricatorApplicationTransactionInterface $object) {
$viewer = $engine->getViewer();
$editor = $object->getApplicationTransactionEditor();
$types = $editor->getTransactionTypesForObject($object);
$types = array_fuse($types);
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($object)
->execute();
$map = array(
PhabricatorTransactions::TYPE_VIEW_POLICY => array(
'key' => 'policy.view',
'aliases' => array('view'),
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
'label' => pht('View Policy'),
'description' => pht('Controls who can view the object.'),
'edit' => 'view',
),
PhabricatorTransactions::TYPE_EDIT_POLICY => array(
'key' => 'policy.edit',
'aliases' => array('edit'),
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
'label' => pht('Edit Policy'),
'description' => pht('Controls who can edit the object.'),
'edit' => 'edit',
),
PhabricatorTransactions::TYPE_JOIN_POLICY => array(
'key' => 'policy.join',
'aliases' => array('join'),
'capability' => PhabricatorPolicyCapability::CAN_JOIN,
'label' => pht('Join Policy'),
'description' => pht('Controls who can join the object.'),
'edit' => 'join',
),
);
$fields = array();
foreach ($map as $type => $spec) {
if (empty($types[$type])) {
continue;
}
$capability = $spec['capability'];
$key = $spec['key'];
$aliases = $spec['aliases'];
$label = $spec['label'];
$description = $spec['description'];
$edit = $spec['edit'];
$policy_field = id(new PhabricatorPolicyEditField())
->setKey($key)
->setLabel($label)
->setDescription($description)
->setAliases($aliases)
->setCapability($capability)
->setPolicies($policies)
->setTransactionType($type)
->setEditTypeKey($edit)
->setValue($object->getPolicy($capability));
$fields[] = $policy_field;
if (!($object instanceof PhabricatorSpacesInterface)) {
if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
$type_space = PhabricatorTransactions::TYPE_SPACE;
if (isset($types[$type_space])) {
$space_field = id(new PhabricatorSpaceEditField())
->setKey('spacePHID')
->setLabel(pht('Space'))
->setEditTypeKey('space')
->setDescription(
pht('Shifts the object in the Spaces application.'))
->setIsReorderable(false)
->setAliases(array('space', 'policy.space'))
->setTransactionType($type_space)
->setValue($object->getSpacePHID());
$fields[] = $space_field;
$policy_field->setSpaceField($space_field);
}
}
}
}
return $fields;
}
}

View file

@ -0,0 +1,60 @@
<?php
final class PhabricatorProjectsEditEngineExtension
extends PhabricatorEditEngineExtension {
const EXTENSIONKEY = 'projects.projects';
public function getExtensionPriority() {
return 500;
}
public function isExtensionEnabled() {
return PhabricatorApplication::isClassInstalled(
'PhabricatorProjectApplication');
}
public function getExtensionName() {
return pht('Projects');
}
public function supportsObject(
PhabricatorEditEngine $engine,
PhabricatorApplicationTransactionInterface $object) {
return ($object instanceof PhabricatorProjectInterface);
}
public function buildCustomEditFields(
PhabricatorEditEngine $engine,
PhabricatorApplicationTransactionInterface $object) {
$edge_type = PhabricatorTransactions::TYPE_EDGE;
$project_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
$object_phid = $object->getPHID();
if ($object_phid) {
$project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
$object_phid,
$project_edge_type);
$project_phids = array_reverse($project_phids);
} else {
$project_phids = array();
}
$projects_field = id(new PhabricatorProjectsEditField())
->setKey('projectPHIDs')
->setLabel(pht('Projects'))
->setEditTypeKey('projects')
->setDescription(pht('Add or remove associated projects.'))
->setAliases(array('project', 'projects'))
->setTransactionType($edge_type)
->setMetadataValue('edge:type', $project_edge_type)
->setValue($project_phids);
return array(
$projects_field,
);
}
}

View file

@ -0,0 +1,56 @@
<?php
final class PhabricatorSubscriptionsEditEngineExtension
extends PhabricatorEditEngineExtension {
const EXTENSIONKEY = 'subscriptions.subscribers';
public function getExtensionPriority() {
return 750;
}
public function isExtensionEnabled() {
return true;
}
public function getExtensionName() {
return pht('Subscriptions');
}
public function supportsObject(
PhabricatorEditEngine $engine,
PhabricatorApplicationTransactionInterface $object) {
return ($object instanceof PhabricatorSubscribableInterface);
}
public function buildCustomEditFields(
PhabricatorEditEngine $engine,
PhabricatorApplicationTransactionInterface $object) {
$subscribers_type = PhabricatorTransactions::TYPE_SUBSCRIBERS;
$object_phid = $object->getPHID();
if ($object_phid) {
$sub_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID(
$object_phid);
} else {
// TODO: Allow applications to provide default subscribers? Maniphest
// does this at a minimum.
$sub_phids = array();
}
$subscribers_field = id(new PhabricatorSubscribersEditField())
->setKey('subscriberPHIDs')
->setLabel(pht('Subscribers'))
->setEditTypeKey('subscribers')
->setDescription(pht('Manage subscribers.'))
->setAliases(array('subscriber', 'subscribers'))
->setTransactionType($subscribers_type)
->setValue($sub_phids);
return array(
$subscribers_field,
);
}
}

View file

@ -73,163 +73,27 @@ abstract class PhabricatorEditEngine
final protected function buildEditFields($object) {
$viewer = $this->getViewer();
$editor = $object->getApplicationTransactionEditor();
$types = $editor->getTransactionTypesForObject($object);
$types = array_fuse($types);
$fields = $this->buildCustomEditFields($object);
if ($object instanceof PhabricatorPolicyInterface) {
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($object)
->execute();
$extensions = PhabricatorEditEngineExtension::getAllEnabledExtensions();
foreach ($extensions as $extension) {
$extension->setViewer($viewer);
$map = array(
PhabricatorTransactions::TYPE_VIEW_POLICY => array(
'key' => 'policy.view',
'aliases' => array('view'),
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
'label' => pht('View Policy'),
'description' => pht('Controls who can view the object.'),
'edit' => 'view',
),
PhabricatorTransactions::TYPE_EDIT_POLICY => array(
'key' => 'policy.edit',
'aliases' => array('edit'),
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
'label' => pht('Edit Policy'),
'description' => pht('Controls who can edit the object.'),
'edit' => 'edit',
),
PhabricatorTransactions::TYPE_JOIN_POLICY => array(
'key' => 'policy.join',
'aliases' => array('join'),
'capability' => PhabricatorPolicyCapability::CAN_JOIN,
'label' => pht('Join Policy'),
'description' => pht('Controls who can join the object.'),
'edit' => 'join',
),
);
foreach ($map as $type => $spec) {
if (empty($types[$type])) {
continue;
}
$capability = $spec['capability'];
$key = $spec['key'];
$aliases = $spec['aliases'];
$label = $spec['label'];
$description = $spec['description'];
$edit = $spec['edit'];
$policy_field = id(new PhabricatorPolicyEditField())
->setKey($key)
->setLabel($label)
->setDescription($description)
->setAliases($aliases)
->setCapability($capability)
->setPolicies($policies)
->setTransactionType($type)
->setEditTypeKey($edit)
->setValue($object->getPolicy($capability));
$fields[] = $policy_field;
if ($object instanceof PhabricatorSpacesInterface) {
if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
$type_space = PhabricatorTransactions::TYPE_SPACE;
if (isset($types[$type_space])) {
$space_field = id(new PhabricatorSpaceEditField())
->setKey('spacePHID')
->setLabel(pht('Space'))
->setEditTypeKey('space')
->setDescription(
pht('Shifts the object in the Spaces application.'))
->setIsReorderable(false)
->setAliases(array('space', 'policy.space'))
->setTransactionType($type_space)
->setValue($object->getSpacePHID());
$fields[] = $space_field;
$policy_field->setSpaceField($space_field);
}
}
}
if (!$extension->supportsObject($this, $object)) {
continue;
}
}
$edge_type = PhabricatorTransactions::TYPE_EDGE;
$object_phid = $object->getPHID();
$extension_fields = $extension->buildCustomEditFields($this, $object);
$project_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
// TODO: Validate this in more detail with a more tailored error.
assert_instances_of($extension_fields, 'PhabricatorEditField');
if ($object instanceof PhabricatorProjectInterface) {
if (isset($types[$edge_type])) {
if ($object_phid) {
$project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
$object_phid,
$project_edge_type);
$project_phids = array_reverse($project_phids);
} else {
$project_phids = array();
}
$edge_field = id(new PhabricatorProjectsEditField())
->setKey('projectPHIDs')
->setLabel(pht('Projects'))
->setEditTypeKey('projects')
->setDescription(pht('Add or remove associated projects.'))
->setAliases(array('project', 'projects'))
->setTransactionType($edge_type)
->setMetadataValue('edge:type', $project_edge_type)
->setValue($project_phids);
$fields[] = $edge_field;
foreach ($extension_fields as $field) {
$fields[] = $field;
}
}
$subscribers_type = PhabricatorTransactions::TYPE_SUBSCRIBERS;
if ($object instanceof PhabricatorSubscribableInterface) {
if (isset($types[$subscribers_type])) {
if ($object_phid) {
$sub_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID(
$object_phid);
} else {
// TODO: Allow applications to provide default subscribers; Maniphest
// does this at a minimum.
$sub_phids = array();
}
$subscribers_field = id(new PhabricatorSubscribersEditField())
->setKey('subscriberPHIDs')
->setLabel(pht('Subscribers'))
->setEditTypeKey('subscribers')
->setDescription(pht('Manage subscribers.'))
->setAliases(array('subscriber', 'subscribers'))
->setTransactionType($subscribers_type)
->setValue($sub_phids);
$fields[] = $subscribers_field;
}
}
$xaction = $object->getApplicationTransactionTemplate();
$comment = $xaction->getApplicationTransactionCommentObject();
if ($comment) {
$comment_type = PhabricatorTransactions::TYPE_COMMENT;
$comment_field = id(new PhabricatorCommentEditField())
->setKey('comment')
->setLabel(pht('Comments'))
->setDescription(pht('Add comments.'))
->setAliases(array('comments'))
->setIsHidden(true)
->setTransactionType($comment_type)
->setValue(null);
$fields[] = $comment_field;
}
$config = $this->getEditEngineConfiguration();
$fields = $config->applyConfigurationToFields($this, $fields);
@ -678,6 +542,8 @@ abstract class PhabricatorEditEngine
$validation_exception = null;
if ($request->isFormPost()) {
foreach ($fields as $field) {
$field->setIsSubmittedForm(true);
if ($field->getIsLocked() || $field->getIsHidden()) {
continue;
}
@ -709,6 +575,20 @@ abstract class PhabricatorEditEngine
->setURI($this->getObjectViewURI($object));
} catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex;
foreach ($fields as $field) {
$xaction_type = $field->getTransactionType();
if ($xaction_type === null) {
continue;
}
$message = $ex->getShortMessage($xaction_type);
if ($message === null) {
continue;
}
$field->setControlError($message);
}
}
} else {
if ($this->getIsCreate()) {

View file

@ -0,0 +1,55 @@
<?php
final class PhabricatorCommentEditEngineExtension
extends PhabricatorEditEngineExtension {
const EXTENSIONKEY = 'transactions.comment';
public function getExtensionPriority() {
return 9000;
}
public function isExtensionEnabled() {
return true;
}
public function getExtensionName() {
return pht('Comments');
}
public function supportsObject(
PhabricatorEditEngine $engine,
PhabricatorApplicationTransactionInterface $object) {
$xaction = $object->getApplicationTransactionTemplate();
try {
$comment = $xaction->getApplicationTransactionCommentObject();
} catch (PhutilMethodNotImplementedException $ex) {
$comment = null;
}
return (bool)$comment;
}
public function buildCustomEditFields(
PhabricatorEditEngine $engine,
PhabricatorApplicationTransactionInterface $object) {
$comment_type = PhabricatorTransactions::TYPE_COMMENT;
$comment_field = id(new PhabricatorCommentEditField())
->setKey('comment')
->setLabel(pht('Comments'))
->setDescription(pht('Add comments.'))
->setAliases(array('comments'))
->setIsHidden(true)
->setTransactionType($comment_type)
->setValue(null);
return array(
$comment_field,
);
}
}

View file

@ -0,0 +1,55 @@
<?php
abstract class PhabricatorEditEngineExtension extends Phobject {
private $viewer;
final public function getExtensionKey() {
return $this->getPhobjectClassConstant('EXTENSIONKEY');
}
final public function setViewer($viewer) {
$this->viewer = $viewer;
return $this;
}
final public function getViewer() {
return $this->viewer;
}
public function getExtensionPriority() {
return 1000;
}
abstract public function isExtensionEnabled();
abstract public function getExtensionName();
abstract public function supportsObject(
PhabricatorEditEngine $engine,
PhabricatorApplicationTransactionInterface $object);
abstract public function buildCustomEditFields(
PhabricatorEditEngine $engine,
PhabricatorApplicationTransactionInterface $object);
final public static function getAllExtensions() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getExtensionKey')
->setSortMethod('getExtensionPriority')
->execute();
}
final public static function getAllEnabledExtensions() {
$extensions = self::getAllExtensions();
foreach ($extensions as $key => $extension) {
if (!$extension->isExtensionEnabled()) {
unset($extensions[$key]);
}
}
return $extensions;
}
}

View file

@ -0,0 +1,52 @@
<?php
final class PhabricatorEditEngineExtensionModule
extends PhabricatorConfigModule {
public function getModuleKey() {
return 'editengine';
}
public function getModuleName() {
return pht('EditEngine Extensions');
}
public function renderModuleStatus(AphrontRequest $request) {
$viewer = $request->getViewer();
$extensions = PhabricatorEditEngineExtension::getAllExtensions();
$rows = array();
foreach ($extensions as $extension) {
$rows[] = array(
$extension->getExtensionPriority(),
get_class($extension),
$extension->getExtensionName(),
$extension->isExtensionEnabled()
? pht('Yes')
: pht('No'),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Priority'),
pht('Class'),
pht('Name'),
pht('Enabled'),
))
->setColumnClasses(
array(
null,
null,
'wide pri',
null,
));
return id(new PHUIObjectBoxView())
->setHeaderText(pht('EditEngine Extensions'))
->setTable($table);
}
}

View file

@ -11,6 +11,9 @@ final class PhabricatorDatasourceEditField
}
public function getDatasource() {
if (!$this->datasource) {
throw new PhutilInvalidStateException('setDatasource');
}
return $this->datasource;
}

View file

@ -13,12 +13,15 @@ abstract class PhabricatorEditField extends Phobject {
private $metadata = array();
private $description;
private $editTypeKey;
private $isRequired;
private $isLocked;
private $isHidden;
private $isPreview;
private $isEditDefaults;
private $isSubmittedForm;
private $controlError;
private $isReorderable = true;
private $isDefaultable = true;
@ -145,6 +148,33 @@ abstract class PhabricatorEditField extends Phobject {
throw new PhutilMethodNotImplementedException();
}
public function setIsSubmittedForm($is_submitted) {
$this->isSubmittedForm = $is_submitted;
return $this;
}
public function getIsSubmittedForm() {
return $this->isSubmittedForm;
}
public function setIsRequired($is_required) {
$this->isRequired = $is_required;
return $this;
}
public function getIsRequired() {
return $this->isRequired;
}
public function setControlError($control_error) {
$this->controlError = $control_error;
return $this;
}
public function getControlError() {
return $this->controlError;
}
protected function renderControl() {
$control = $this->newControl();
if ($control === null) {
@ -176,6 +206,16 @@ abstract class PhabricatorEditField extends Phobject {
$control->setDisabled($disabled);
if ($this->getIsSubmittedForm()) {
$error = $this->getControlError();
if ($error !== null) {
$control->setError($error);
}
} else if ($this->getIsRequired()) {
$control->setError(true);
}
return $control;
}