diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index b4cc9ac1a7..791f26dc23 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -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', diff --git a/src/applications/policy/editor/PhabricatorPolicyEditEngineExtension.php b/src/applications/policy/editor/PhabricatorPolicyEditEngineExtension.php new file mode 100644 index 0000000000..21ea34ca28 --- /dev/null +++ b/src/applications/policy/editor/PhabricatorPolicyEditEngineExtension.php @@ -0,0 +1,118 @@ +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; + } + +} diff --git a/src/applications/project/editor/PhabricatorProjectsEditEngineExtension.php b/src/applications/project/editor/PhabricatorProjectsEditEngineExtension.php new file mode 100644 index 0000000000..78ade7e797 --- /dev/null +++ b/src/applications/project/editor/PhabricatorProjectsEditEngineExtension.php @@ -0,0 +1,60 @@ +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, + ); + } + +} diff --git a/src/applications/subscriptions/editor/PhabricatorSubscriptionsEditEngineExtension.php b/src/applications/subscriptions/editor/PhabricatorSubscriptionsEditEngineExtension.php new file mode 100644 index 0000000000..6532ed2521 --- /dev/null +++ b/src/applications/subscriptions/editor/PhabricatorSubscriptionsEditEngineExtension.php @@ -0,0 +1,56 @@ +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, + ); + } + +} diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php index 0454d8f49e..59ca02f313 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -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()) { diff --git a/src/applications/transactions/editengineextension/PhabricatorCommentEditEngineExtension.php b/src/applications/transactions/editengineextension/PhabricatorCommentEditEngineExtension.php new file mode 100644 index 0000000000..6837d8e933 --- /dev/null +++ b/src/applications/transactions/editengineextension/PhabricatorCommentEditEngineExtension.php @@ -0,0 +1,55 @@ +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, + ); + } + +} diff --git a/src/applications/transactions/editengineextension/PhabricatorEditEngineExtension.php b/src/applications/transactions/editengineextension/PhabricatorEditEngineExtension.php new file mode 100644 index 0000000000..9a799d4e5b --- /dev/null +++ b/src/applications/transactions/editengineextension/PhabricatorEditEngineExtension.php @@ -0,0 +1,55 @@ +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; + } + +} diff --git a/src/applications/transactions/editengineextension/PhabricatorEditEngineExtensionModule.php b/src/applications/transactions/editengineextension/PhabricatorEditEngineExtensionModule.php new file mode 100644 index 0000000000..98a4e0cb3b --- /dev/null +++ b/src/applications/transactions/editengineextension/PhabricatorEditEngineExtensionModule.php @@ -0,0 +1,52 @@ +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); + } + +} diff --git a/src/applications/transactions/editfield/PhabricatorDatasourceEditField.php b/src/applications/transactions/editfield/PhabricatorDatasourceEditField.php index f3cf5fe079..d32716bfa5 100644 --- a/src/applications/transactions/editfield/PhabricatorDatasourceEditField.php +++ b/src/applications/transactions/editfield/PhabricatorDatasourceEditField.php @@ -11,6 +11,9 @@ final class PhabricatorDatasourceEditField } public function getDatasource() { + if (!$this->datasource) { + throw new PhutilInvalidStateException('setDatasource'); + } return $this->datasource; } diff --git a/src/applications/transactions/editfield/PhabricatorEditField.php b/src/applications/transactions/editfield/PhabricatorEditField.php index fcf66c3883..1378ab4a39 100644 --- a/src/applications/transactions/editfield/PhabricatorEditField.php +++ b/src/applications/transactions/editfield/PhabricatorEditField.php @@ -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; }