<?php

final class PhabricatorSubtypeEditEngineExtension
  extends PhabricatorEditEngineExtension {

  const EXTENSIONKEY = 'editengine.subtype';
  const EDITKEY = 'subtype';

  public function getExtensionPriority() {
    return 8000;
  }

  public function isExtensionEnabled() {
    return true;
  }

  public function getExtensionName() {
    return pht('Subtypes');
  }

  public function supportsObject(
    PhabricatorEditEngine $engine,
    PhabricatorApplicationTransactionInterface $object) {
    return $engine->supportsSubtypes();
  }

  public function buildCustomEditFields(
    PhabricatorEditEngine $engine,
    PhabricatorApplicationTransactionInterface $object) {

    $subtype_type = PhabricatorTransactions::TYPE_SUBTYPE;

    $map = $object->newEditEngineSubtypeMap();
    $options = mpull($map, 'getName');

    $subtype_field = id(new PhabricatorSelectEditField())
      ->setKey(self::EDITKEY)
      ->setLabel(pht('Subtype'))
      ->setIsConduitOnly(true)
      ->setIsHidden(true)
      ->setIsReorderable(false)
      ->setIsDefaultable(false)
      ->setIsLockable(false)
      ->setTransactionType($subtype_type)
      ->setConduitDescription(pht('Change the object subtype.'))
      ->setConduitTypeDescription(pht('New object subtype key.'))
      ->setValue($object->getEditEngineSubtype())
      ->setOptions($options);

    return array(
      $subtype_field,
    );
  }

}

<?php

final class PhabricatorSubtypeEditEngineExtension
  extends PhabricatorEditEngineExtension {

  const EXTENSIONKEY = 'editengine.subtype';
  const EDITKEY = 'subtype';

  public function getExtensionPriority() {
    return 8000;
  }

  public function isExtensionEnabled() {
    return true;
  }

  public function getExtensionName() {
    return pht('Subtypes');
  }

  public function supportsObject(
    PhabricatorEditEngine $engine,
    PhabricatorApplicationTransactionInterface $object) {
    return $engine->supportsSubtypes();
  }

  public function buildCustomEditFields(
    PhabricatorEditEngine $engine,
    PhabricatorApplicationTransactionInterface $object) {

    $subtype_type = PhabricatorTransactions::TYPE_SUBTYPE;

    $map = $object->newEditEngineSubtypeMap();
    $options = mpull($map, 'getName');

    $subtype_field = id(new PhabricatorSelectEditField())
      ->setKey(self::EDITKEY)
      ->setLabel(pht('Subtype'))
      ->setIsConduitOnly(true)
      ->setIsHidden(true)
      ->setIsReorderable(false)
      ->setIsDefaultable(false)
      ->setIsLockable(false)
      ->setTransactionType($subtype_type)
      ->setConduitDescription(pht('Change the object subtype.'))
      ->setConduitTypeDescription(pht('New object subtype key.'))
      ->setValue($object->getEditEngineSubtype())
      ->setOptions($options);

    // If subtypes are configured, enable changing them from the bulk editor.
    if (count($map) > 1) {
      $subtype_field->setBulkEditLabel(pht('Change subtype to'));
    }

    return array(
      $subtype_field,
    );
  }

}

Allow object subtypes to be changed via bulk editor
Allow object subtypes to be changed via bulk editor

Summary:
Ref T13151. See PHI683. Ref T12314.

You can currently change object subtypes via Conduit (`maniphest.edit`) but not via the web UI.

Changing object subtypes is inherently a somewhat-perilous operation that likely has a lot of rough edges we'll need to smooth over eventually, mostly around changing an object from subtype X to subtype Y, where some field exists on one but not the other. This isn't a huge issue, just not entirely intuitive.

It should also, in theory, be fairly rare.

As a reasonable middle ground, provide web UI access via the bulk editor. This makes it possible, but doesn't clutter the UI up with a rarely-used option with rough edges.

Test Plan:
  - With subtypes not configured, saw a normal bulk editor with no new option.
  - With subtypes configured, swapped tasks subtypes via bulk editor.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13151, T12314

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