Changeset View
Changeset View
Standalone View
Standalone View
src/applications/transactions/editengine/PhabricatorEditEngine.php
- This file was moved from src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php.
| <?php | <?php | ||||
| /** | /** | ||||
| * @task fields Managing Fields | * @task fields Managing Fields | ||||
| * @task text Display Text | * @task text Display Text | ||||
| * @task config Edit Engine Configuration | |||||
| * @task uri Managing URIs | * @task uri Managing URIs | ||||
| * @task load Creating and Loading Objects | * @task load Creating and Loading Objects | ||||
| * @task web Responding to Web Requests | * @task web Responding to Web Requests | ||||
| * @task edit Responding to Edit Requests | * @task edit Responding to Edit Requests | ||||
| * @task http Responding to HTTP Parameter Requests | * @task http Responding to HTTP Parameter Requests | ||||
| * @task conduit Responding to Conduit Requests | * @task conduit Responding to Conduit Requests | ||||
| */ | */ | ||||
| abstract class PhabricatorApplicationEditEngine extends Phobject { | abstract class PhabricatorEditEngine | ||||
| extends Phobject | |||||
| implements PhabricatorPolicyInterface { | |||||
| const EDITENGINECONFIG_DEFAULT = 'default'; | |||||
| private $viewer; | private $viewer; | ||||
| private $controller; | private $controller; | ||||
| private $isCreate; | private $isCreate; | ||||
| private $editEngineConfiguration; | |||||
| final public function setViewer(PhabricatorUser $viewer) { | final public function setViewer(PhabricatorUser $viewer) { | ||||
| $this->viewer = $viewer; | $this->viewer = $viewer; | ||||
| return $this; | return $this; | ||||
| } | } | ||||
| final public function getViewer() { | final public function getViewer() { | ||||
| return $this->viewer; | return $this->viewer; | ||||
| } | } | ||||
| final public function setController(PhabricatorController $controller) { | final public function setController(PhabricatorController $controller) { | ||||
| $this->controller = $controller; | $this->controller = $controller; | ||||
| $this->setViewer($controller->getViewer()); | $this->setViewer($controller->getViewer()); | ||||
| return $this; | return $this; | ||||
| } | } | ||||
| final public function getController() { | final public function getController() { | ||||
| return $this->controller; | return $this->controller; | ||||
| } | } | ||||
| final public function getEngineKey() { | |||||
| return $this->getPhobjectClassConstant('ENGINECONST', 64); | |||||
| } | |||||
| /* -( Managing Fields )---------------------------------------------------- */ | /* -( Managing Fields )---------------------------------------------------- */ | ||||
| abstract protected function buildCustomEditFields($object); | abstract protected function buildCustomEditFields($object); | ||||
| final protected function buildEditFields($object) { | final protected function buildEditFields($object) { | ||||
| $viewer = $this->getViewer(); | $viewer = $this->getViewer(); | ||||
| ▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Lines | if ($object instanceof PhabricatorSubscribableInterface) { | ||||
| ->setDescription(pht('Manage subscribers.')) | ->setDescription(pht('Manage subscribers.')) | ||||
| ->setAliases(array('subscriber', 'subscribers')) | ->setAliases(array('subscriber', 'subscribers')) | ||||
| ->setTransactionType($subscribers_type) | ->setTransactionType($subscribers_type) | ||||
| ->setValue($sub_phids); | ->setValue($sub_phids); | ||||
| $fields[] = $subscribers_field; | $fields[] = $subscribers_field; | ||||
| } | } | ||||
| } | } | ||||
| $config = $this->getEditEngineConfiguration(); | |||||
| $fields = $config->applyConfigurationToFields($this, $fields); | |||||
| foreach ($fields as $field) { | foreach ($fields as $field) { | ||||
| $field | $field | ||||
| ->setViewer($viewer) | ->setViewer($viewer) | ||||
| ->setObject($object); | ->setObject($object); | ||||
| } | } | ||||
| return $fields; | return $fields; | ||||
| } | } | ||||
| /* -( Display Text )------------------------------------------------------- */ | /* -( Display Text )------------------------------------------------------- */ | ||||
| /** | /** | ||||
| * @task text | * @task text | ||||
| */ | */ | ||||
| abstract public function getEngineName(); | |||||
| /** | |||||
| * @task text | |||||
| */ | |||||
| abstract protected function getObjectCreateTitleText($object); | abstract protected function getObjectCreateTitleText($object); | ||||
| /** | /** | ||||
| * @task text | * @task text | ||||
| */ | */ | ||||
| abstract protected function getObjectEditTitleText($object); | abstract protected function getObjectEditTitleText($object); | ||||
| /** | /** | ||||
| * @task text | * @task text | ||||
| */ | */ | ||||
| abstract protected function getObjectCreateShortText($object); | abstract protected function getObjectCreateShortText(); | ||||
| /** | /** | ||||
| * @task text | * @task text | ||||
| */ | */ | ||||
| abstract protected function getObjectEditShortText($object); | abstract protected function getObjectEditShortText($object); | ||||
| /** | /** | ||||
| * @task text | * @task text | ||||
| */ | */ | ||||
| protected function getObjectCreateButtonText($object) { | protected function getObjectCreateButtonText($object) { | ||||
| return $this->getObjectCreateTitleText($object); | return $this->getObjectCreateTitleText($object); | ||||
| } | } | ||||
| /** | /** | ||||
| * @task text | * @task text | ||||
| */ | */ | ||||
| protected function getObjectEditButtonText($object) { | protected function getObjectEditButtonText($object) { | ||||
| return pht('Save Changes'); | return pht('Save Changes'); | ||||
| } | } | ||||
| /* -( Edit Engine Configuration )------------------------------------------ */ | |||||
| protected function supportsEditEngineConfiguration() { | |||||
| return true; | |||||
| } | |||||
| final protected function getEditEngineConfiguration() { | |||||
| return $this->editEngineConfiguration; | |||||
| } | |||||
| private function loadEditEngineConfiguration($key) { | |||||
| if ($key === null) { | |||||
| $key = self::EDITENGINECONFIG_DEFAULT; | |||||
| } | |||||
| $config = id(new PhabricatorEditEngineConfigurationQuery()) | |||||
| ->setViewer($this->getViewer()) | |||||
| ->withEngineKeys(array($this->getEngineKey())) | |||||
| ->withIdentifiers(array($key)) | |||||
| ->executeOne(); | |||||
| if (!$config) { | |||||
| return null; | |||||
| } | |||||
| $this->editEngineConfiguration = $config; | |||||
| return $config; | |||||
| } | |||||
| final public function getBuiltinEngineConfigurations() { | |||||
| $configurations = $this->newBuiltinEngineConfigurations(); | |||||
| if (!$configurations) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'EditEngine ("%s") returned no builtin engine configurations, but '. | |||||
| 'an edit engine must have at least one configuration.', | |||||
| get_class($this))); | |||||
| } | |||||
| assert_instances_of($configurations, 'PhabricatorEditEngineConfiguration'); | |||||
| $has_default = false; | |||||
| foreach ($configurations as $config) { | |||||
| if ($config->getBuiltinKey() == self::EDITENGINECONFIG_DEFAULT) { | |||||
| $has_default = true; | |||||
| } | |||||
| } | |||||
| if (!$has_default) { | |||||
| $first = head($configurations); | |||||
| if (!$first->getBuiltinKey()) { | |||||
| $first->setBuiltinKey(self::EDITENGINECONFIG_DEFAULT); | |||||
| if (!strlen($first->getName())) { | |||||
| $first->setName($this->getObjectCreateShortText()); | |||||
| } | |||||
| } else { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'EditEngine ("%s") returned builtin engine configurations, '. | |||||
| 'but none are marked as default and the first configuration has '. | |||||
| 'a different builtin key already. Mark a builtin as default or '. | |||||
| 'omit the key from the first configuration', | |||||
| get_class($this))); | |||||
| } | |||||
| } | |||||
| $builtins = array(); | |||||
| foreach ($configurations as $key => $config) { | |||||
| $builtin_key = $config->getBuiltinKey(); | |||||
| if ($builtin_key === null) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'EditEngine ("%s") returned builtin engine configurations, '. | |||||
| 'but one (with key "%s") is missing a builtin key. Provide a '. | |||||
| 'builtin key for each configuration (you can omit it from the '. | |||||
| 'first configuration in the list to automatically assign the '. | |||||
| 'default key).', | |||||
| get_class($this), | |||||
| $key)); | |||||
| } | |||||
| if (isset($builtins[$builtin_key])) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'EditEngine ("%s") returned builtin engine configurations, '. | |||||
| 'but at least two specify the same builtin key ("%s"). Engines '. | |||||
| 'must have unique builtin keys.', | |||||
| get_class($this), | |||||
| $builtin_key)); | |||||
| } | |||||
| $builtins[$builtin_key] = $config; | |||||
| } | |||||
| return $builtins; | |||||
| } | |||||
| protected function newBuiltinEngineConfigurations() { | |||||
| return array( | |||||
| $this->newConfiguration(), | |||||
| ); | |||||
| } | |||||
| final protected function newConfiguration() { | |||||
| return PhabricatorEditEngineConfiguration::initializeNewConfiguration( | |||||
| $this->getViewer(), | |||||
| $this); | |||||
| } | |||||
| /* -( Managing URIs )------------------------------------------------------ */ | /* -( Managing URIs )------------------------------------------------------ */ | ||||
| /** | /** | ||||
| * @task uri | * @task uri | ||||
| */ | */ | ||||
| abstract protected function getObjectViewURI($object); | abstract protected function getObjectViewURI($object); | ||||
| ▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | /* -( Creating and Loading Objects )--------------------------------------- */ | ||||
| /** | /** | ||||
| * Test if this workflow is creating a new object or editing an existing one. | * Test if this workflow is creating a new object or editing an existing one. | ||||
| * | * | ||||
| * @return bool True if a new object is being created. | * @return bool True if a new object is being created. | ||||
| * @task load | * @task load | ||||
| */ | */ | ||||
| final protected function getIsCreate() { | final public function getIsCreate() { | ||||
| return $this->isCreate; | return $this->isCreate; | ||||
| } | } | ||||
| /** | /** | ||||
| * Flag this workflow as a create or edit. | * Flag this workflow as a create or edit. | ||||
| * | * | ||||
| * @param bool True if this is a create workflow. | * @param bool True if this is a create workflow. | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | private function newObjectFromQuery(PhabricatorPolicyAwareQuery $query) { | ||||
| if (!$object) { | if (!$object) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return $object; | return $object; | ||||
| } | } | ||||
| /** | |||||
| * Verify that an object is appropriate for editing. | |||||
| * | |||||
| * @param wild Loaded value. | |||||
| * @return void | |||||
| * @task load | |||||
| */ | |||||
| private function validateObject($object) { | |||||
| if (!$object || !is_object($object)) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'EditEngine "%s" created or loaded an invalid object: object must '. | |||||
| 'actually be an object, but is of some other type ("%s").', | |||||
| get_class($this), | |||||
| gettype($object))); | |||||
| } | |||||
| if (!($object instanceof PhabricatorApplicationTransactionInterface)) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'EditEngine "%s" created or loaded an invalid object: object (of '. | |||||
| 'class "%s") must implement "%s", but does not.', | |||||
| get_class($this), | |||||
| get_class($object), | |||||
| 'PhabricatorApplicationTransactionInterface')); | |||||
| } | |||||
| } | |||||
| /* -( Responding to Web Requests )----------------------------------------- */ | /* -( Responding to Web Requests )----------------------------------------- */ | ||||
| final public function buildResponse() { | final public function buildResponse() { | ||||
| $viewer = $this->getViewer(); | $viewer = $this->getViewer(); | ||||
| $controller = $this->getController(); | $controller = $this->getController(); | ||||
| $request = $controller->getRequest(); | $request = $controller->getRequest(); | ||||
| $config = $this->loadEditEngineConfiguration($request->getURIData('form')); | |||||
| if (!$config) { | |||||
| return new Aphront404Response(); | |||||
| } | |||||
| $id = $request->getURIData('id'); | $id = $request->getURIData('id'); | ||||
| if ($id) { | if ($id) { | ||||
| $this->setIsCreate(false); | $this->setIsCreate(false); | ||||
| $object = $this->newObjectFromID($id); | $object = $this->newObjectFromID($id); | ||||
| if (!$object) { | if (!$object) { | ||||
| return new Aphront404Response(); | return new Aphront404Response(); | ||||
| } | } | ||||
| } else { | } else { | ||||
| $this->setIsCreate(true); | $this->setIsCreate(true); | ||||
| $object = $this->newEditableObject(); | $object = $this->newEditableObject(); | ||||
| } | } | ||||
| $this->validateObject($object); | |||||
| $action = $request->getURIData('editAction'); | $action = $request->getURIData('editAction'); | ||||
| switch ($action) { | switch ($action) { | ||||
| case 'parameters': | case 'parameters': | ||||
| return $this->buildParametersResponse($object); | return $this->buildParametersResponse($object); | ||||
| default: | default: | ||||
| return $this->buildEditResponse($object); | return $this->buildEditResponse($object); | ||||
| } | } | ||||
| } | } | ||||
| private function buildCrumbs($object, $final = false) { | private function buildCrumbs($object, $final = false) { | ||||
| $controller = $this->getcontroller(); | $controller = $this->getcontroller(); | ||||
| $crumbs = $controller->buildApplicationCrumbsForEditEngine(); | $crumbs = $controller->buildApplicationCrumbsForEditEngine(); | ||||
| if ($this->getIsCreate()) { | if ($this->getIsCreate()) { | ||||
| $create_text = $this->getObjectCreateShortText($object); | $create_text = $this->getObjectCreateShortText(); | ||||
| if ($final) { | if ($final) { | ||||
| $crumbs->addTextCrumb($create_text); | $crumbs->addTextCrumb($create_text); | ||||
| } else { | } else { | ||||
| $edit_uri = $this->getEditURI($object); | $edit_uri = $this->getEditURI($object); | ||||
| $crumbs->addTextCrumb($create_text, $edit_uri); | $crumbs->addTextCrumb($create_text, $edit_uri); | ||||
| } | } | ||||
| } else { | } else { | ||||
| $crumbs->addTextCrumb( | $crumbs->addTextCrumb( | ||||
| ▲ Show 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | $action_button = id(new PHUIButtonView()) | ||||
| ->setDropdownMenu($action_view); | ->setDropdownMenu($action_view); | ||||
| return $action_button; | return $action_button; | ||||
| } | } | ||||
| private function buildEditFormActions($object) { | private function buildEditFormActions($object) { | ||||
| $actions = array(); | $actions = array(); | ||||
| if ($this->supportsEditEngineConfiguration()) { | |||||
| $engine_key = $this->getEngineKey(); | |||||
| $config = $this->getEditEngineConfiguration(); | |||||
| $actions[] = id(new PhabricatorActionView()) | |||||
| ->setName(pht('Manage Form Configurations')) | |||||
| ->setIcon('fa-list-ul') | |||||
| ->setHref("/transactions/editengine/{$engine_key}/"); | |||||
| $actions[] = id(new PhabricatorActionView()) | |||||
| ->setName(pht('Edit Form Configuration')) | |||||
| ->setIcon('fa-pencil') | |||||
| ->setHref($config->getURI()); | |||||
| } | |||||
| $actions[] = id(new PhabricatorActionView()) | $actions[] = id(new PhabricatorActionView()) | ||||
| ->setName(pht('Show HTTP Parameters')) | ->setName(pht('Show HTTP Parameters')) | ||||
| ->setIcon('fa-crosshairs') | ->setIcon('fa-crosshairs') | ||||
| ->setHref($this->getEditURI($object, 'parameters/')); | ->setHref($this->getEditURI($object, 'parameters/')); | ||||
| return $actions; | return $actions; | ||||
| } | } | ||||
| Show All 15 Lines | private function buildParametersResponse($object) { | ||||
| $fields = $this->buildEditFields($object); | $fields = $this->buildEditFields($object); | ||||
| $crumbs = $this->buildCrumbs($object); | $crumbs = $this->buildCrumbs($object); | ||||
| $crumbs->addTextCrumb(pht('HTTP Parameters')); | $crumbs->addTextCrumb(pht('HTTP Parameters')); | ||||
| $crumbs->setBorder(true); | $crumbs->setBorder(true); | ||||
| $header_text = pht( | $header_text = pht( | ||||
| 'HTTP Parameters: %s', | 'HTTP Parameters: %s', | ||||
| $this->getObjectCreateShortText($object)); | $this->getObjectCreateShortText()); | ||||
| $header = id(new PHUIHeaderView()) | $header = id(new PHUIHeaderView()) | ||||
| ->setHeader($header_text); | ->setHeader($header_text); | ||||
| $help_view = id(new PhabricatorApplicationEditHTTPParameterHelpView()) | $help_view = id(new PhabricatorApplicationEditHTTPParameterHelpView()) | ||||
| ->setUser($viewer) | ->setUser($viewer) | ||||
| ->setFields($fields); | ->setFields($fields); | ||||
| Show All 19 Lines | /* -( Conduit )------------------------------------------------------------ */ | ||||
| * This method accepts a list of transactions to apply to an object, and | * This method accepts a list of transactions to apply to an object, and | ||||
| * either edits an existing object or creates a new one. | * either edits an existing object or creates a new one. | ||||
| * | * | ||||
| * @task conduit | * @task conduit | ||||
| */ | */ | ||||
| final public function buildConduitResponse(ConduitAPIRequest $request) { | final public function buildConduitResponse(ConduitAPIRequest $request) { | ||||
| $viewer = $this->getViewer(); | $viewer = $this->getViewer(); | ||||
| $config = $this->loadEditEngineConfiguration(null); | |||||
| if (!$config) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'Unable to load configuration for this EditEngine ("%s").', | |||||
| get_class($this))); | |||||
| } | |||||
| $phid = $request->getValue('objectPHID'); | $phid = $request->getValue('objectPHID'); | ||||
| if ($phid) { | if ($phid) { | ||||
| $this->setIsCreate(false); | $this->setIsCreate(false); | ||||
| $object = $this->newObjectFromPHID($phid); | $object = $this->newObjectFromPHID($phid); | ||||
| if (!$object) { | if (!$object) { | ||||
| throw new Exception(pht('No such object with PHID "%s".', $phid)); | throw new Exception(pht('No such object with PHID "%s".', $phid)); | ||||
| } | } | ||||
| } else { | } else { | ||||
| $this->setIsCreate(true); | $this->setIsCreate(true); | ||||
| $object = $this->newEditableObject(); | $object = $this->newEditableObject(); | ||||
| } | } | ||||
| $this->validateObject($object); | |||||
| $fields = $this->buildEditFields($object); | $fields = $this->buildEditFields($object); | ||||
| $types = $this->getAllEditTypesFromFields($fields); | $types = $this->getAllEditTypesFromFields($fields); | ||||
| $template = $object->getApplicationTransactionTemplate(); | $template = $object->getApplicationTransactionTemplate(); | ||||
| $xactions = $this->getConduitTransactions($request, $types, $template); | $xactions = $this->getConduitTransactions($request, $types, $template); | ||||
| $editor = $object->getApplicationTransactionEditor() | $editor = $object->getApplicationTransactionEditor() | ||||
| ▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | /* -( Conduit )------------------------------------------------------------ */ | ||||
| } | } | ||||
| public function getAllEditTypes() { | public function getAllEditTypes() { | ||||
| $object = $this->newEditableObject(); | $object = $this->newEditableObject(); | ||||
| $fields = $this->buildEditFields($object); | $fields = $this->buildEditFields($object); | ||||
| return $this->getAllEditTypesFromFields($fields); | return $this->getAllEditTypesFromFields($fields); | ||||
| } | } | ||||
| final public static function getAllEditEngines() { | |||||
| return id(new PhutilClassMapQuery()) | |||||
| ->setAncestorClass(__CLASS__) | |||||
| ->setUniqueMethod('getEngineKey') | |||||
| ->execute(); | |||||
| } | |||||
| final public static function getByKey(PhabricatorUser $viewer, $key) { | |||||
| return id(new PhabricatorEditEngineQuery()) | |||||
| ->setViewer($viewer) | |||||
| ->withEngineKeys(array($key)) | |||||
| ->executeOne(); | |||||
| } | |||||
| /* -( PhabricatorPolicyInterface )----------------------------------------- */ | |||||
| public function getPHID() { | |||||
| return get_class($this); | |||||
| } | |||||
| public function getCapabilities() { | |||||
| return array( | |||||
| PhabricatorPolicyCapability::CAN_VIEW, | |||||
| ); | |||||
| } | |||||
| public function getPolicy($capability) { | |||||
| switch ($capability) { | |||||
| case PhabricatorPolicyCapability::CAN_VIEW: | |||||
| return PhabricatorPolicies::getMostOpenPolicy(); | |||||
| } | |||||
| } | |||||
| public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { | |||||
| return false; | |||||
| } | |||||
| public function describeAutomaticCapability($capability) { | |||||
| return null; | |||||
| } | |||||
| } | } | ||||