From 7d4b323da2bd6ba7f110ad4b88c2d775e2a55f97 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 25 Feb 2016 05:05:36 -0800 Subject: [PATCH] Store Almanac "service types" instead of "service classes" Summary: Ref T10449. Currently, we store classes (like "AlmanacClusterRepositoryServiceType") in the database. Instead, store types (like "cluster.repository"). This is a small change, but types are a little more flexible (they let us freely reanme classes), a little cleaner (fewer magic strings in the codebase), and a little better for API usage (they're more human readable). Make this minor usability change now, before we unprototype. Also make services searchable by type. Also remove old Almanac API endpoints. Test Plan: - Ran migration, verified all data migrated properly. - Created, edited, rebound, and changed properties of services. - Searched for services by service type. - Reviewed available Conduit methods. Reviewers: chad Reviewed By: chad Subscribers: yelirekim Maniphest Tasks: T10449 Differential Revision: https://secure.phabricator.com/D15346 --- .../autopatches/20160225.almanac.2.stype.sql | 2 + .../autopatches/20160225.almanac.3.stype.php | 30 +++++++ src/__phutil_library_map__.php | 8 +- .../conduit/AlmanacConduitAPIMethod.php | 73 ---------------- .../AlmanacQueryDevicesConduitAPIMethod.php | 63 -------------- .../AlmanacQueryServicesConduitAPIMethod.php | 86 ------------------- .../AlmanacServiceEditController.php | 26 +++--- .../AlmanacServiceViewController.php | 2 +- .../almanac/query/AlmanacServiceQuery.php | 24 +++--- .../query/AlmanacServiceSearchEngine.php | 15 +++- .../AlmanacClusterDatabaseServiceType.php | 2 + .../AlmanacClusterRepositoryServiceType.php | 2 + .../servicetype/AlmanacCustomServiceType.php | 2 + .../AlmanacDrydockPoolServiceType.php | 2 + .../servicetype/AlmanacServiceType.php | 8 +- .../almanac/storage/AlmanacProperty.php | 40 +++++++++ .../almanac/storage/AlmanacService.php | 56 +++++++++--- .../typeahead/AlmanacServiceDatasource.php | 6 +- .../AlmanacServiceTypeDatasource.php | 43 ++++++++++ .../PhabricatorRepositoriesSetupCheck.php | 4 +- .../DiffusionRepositoryCreateController.php | 4 +- ...anacServiceHostBlueprintImplementation.php | 8 +- .../storage/PhabricatorRepository.php | 2 +- 23 files changed, 226 insertions(+), 282 deletions(-) create mode 100644 resources/sql/autopatches/20160225.almanac.2.stype.sql create mode 100644 resources/sql/autopatches/20160225.almanac.3.stype.php delete mode 100644 src/applications/almanac/conduit/AlmanacConduitAPIMethod.php delete mode 100644 src/applications/almanac/conduit/AlmanacQueryDevicesConduitAPIMethod.php delete mode 100644 src/applications/almanac/conduit/AlmanacQueryServicesConduitAPIMethod.php create mode 100644 src/applications/almanac/typeahead/AlmanacServiceTypeDatasource.php diff --git a/resources/sql/autopatches/20160225.almanac.2.stype.sql b/resources/sql/autopatches/20160225.almanac.2.stype.sql new file mode 100644 index 0000000000..fcd054ff23 --- /dev/null +++ b/resources/sql/autopatches/20160225.almanac.2.stype.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_almanac.almanac_service + CHANGE serviceClass serviceType VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20160225.almanac.3.stype.php b/resources/sql/autopatches/20160225.almanac.3.stype.php new file mode 100644 index 0000000000..f6f19eabd3 --- /dev/null +++ b/resources/sql/autopatches/20160225.almanac.3.stype.php @@ -0,0 +1,30 @@ +establishConnection('w'); + +foreach (new LiskMigrationIterator($table) as $service) { + + $new_type = null; + try { + $old_type = $service->getServiceType(); + $object = newv($old_type, array()); + $new_type = $object->getServiceTypeConstant(); + } catch (Exception $ex) { + continue; + } + + if (!$new_type) { + continue; + } + + queryfx( + $conn_w, + 'UPDATE %T SET serviceType = %s WHERE id = %d', + $table->getTableName(), + $new_type, + $service->getID()); +} diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index c63eaa4b57..d01c2d6af9 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -25,7 +25,6 @@ phutil_register_library_map(array( 'AlmanacClusterDatabaseServiceType' => 'applications/almanac/servicetype/AlmanacClusterDatabaseServiceType.php', 'AlmanacClusterRepositoryServiceType' => 'applications/almanac/servicetype/AlmanacClusterRepositoryServiceType.php', 'AlmanacClusterServiceType' => 'applications/almanac/servicetype/AlmanacClusterServiceType.php', - 'AlmanacConduitAPIMethod' => 'applications/almanac/conduit/AlmanacConduitAPIMethod.php', 'AlmanacConsoleController' => 'applications/almanac/controller/AlmanacConsoleController.php', 'AlmanacController' => 'applications/almanac/controller/AlmanacController.php', 'AlmanacCreateDevicesCapability' => 'applications/almanac/capability/AlmanacCreateDevicesCapability.php', @@ -101,8 +100,6 @@ phutil_register_library_map(array( 'AlmanacPropertyInterface' => 'applications/almanac/property/AlmanacPropertyInterface.php', 'AlmanacPropertyQuery' => 'applications/almanac/query/AlmanacPropertyQuery.php', 'AlmanacQuery' => 'applications/almanac/query/AlmanacQuery.php', - 'AlmanacQueryDevicesConduitAPIMethod' => 'applications/almanac/conduit/AlmanacQueryDevicesConduitAPIMethod.php', - 'AlmanacQueryServicesConduitAPIMethod' => 'applications/almanac/conduit/AlmanacQueryServicesConduitAPIMethod.php', 'AlmanacSchemaSpec' => 'applications/almanac/storage/AlmanacSchemaSpec.php', 'AlmanacSearchEngineAttachment' => 'applications/almanac/engineextension/AlmanacSearchEngineAttachment.php', 'AlmanacService' => 'applications/almanac/storage/AlmanacService.php', @@ -120,6 +117,7 @@ phutil_register_library_map(array( 'AlmanacServiceTransaction' => 'applications/almanac/storage/AlmanacServiceTransaction.php', 'AlmanacServiceTransactionQuery' => 'applications/almanac/query/AlmanacServiceTransactionQuery.php', 'AlmanacServiceType' => 'applications/almanac/servicetype/AlmanacServiceType.php', + 'AlmanacServiceTypeDatasource' => 'applications/almanac/typeahead/AlmanacServiceTypeDatasource.php', 'AlmanacServiceTypeTestCase' => 'applications/almanac/servicetype/__tests__/AlmanacServiceTypeTestCase.php', 'AlmanacServiceViewController' => 'applications/almanac/controller/AlmanacServiceViewController.php', 'AlmanacTransaction' => 'applications/almanac/storage/AlmanacTransaction.php', @@ -4012,7 +4010,6 @@ phutil_register_library_map(array( 'AlmanacClusterDatabaseServiceType' => 'AlmanacClusterServiceType', 'AlmanacClusterRepositoryServiceType' => 'AlmanacClusterServiceType', 'AlmanacClusterServiceType' => 'AlmanacServiceType', - 'AlmanacConduitAPIMethod' => 'ConduitAPIMethod', 'AlmanacConsoleController' => 'AlmanacController', 'AlmanacController' => 'PhabricatorController', 'AlmanacCreateDevicesCapability' => 'PhabricatorPolicyCapability', @@ -4120,8 +4117,6 @@ phutil_register_library_map(array( 'AlmanacPropertyEditEngine' => 'PhabricatorEditEngine', 'AlmanacPropertyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'AlmanacQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'AlmanacQueryDevicesConduitAPIMethod' => 'AlmanacConduitAPIMethod', - 'AlmanacQueryServicesConduitAPIMethod' => 'AlmanacConduitAPIMethod', 'AlmanacSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'AlmanacSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'AlmanacService' => array( @@ -4149,6 +4144,7 @@ phutil_register_library_map(array( 'AlmanacServiceTransaction' => 'AlmanacTransaction', 'AlmanacServiceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacServiceType' => 'Phobject', + 'AlmanacServiceTypeDatasource' => 'PhabricatorTypeaheadDatasource', 'AlmanacServiceTypeTestCase' => 'PhabricatorTestCase', 'AlmanacServiceViewController' => 'AlmanacServiceController', 'AlmanacTransaction' => 'PhabricatorApplicationTransaction', diff --git a/src/applications/almanac/conduit/AlmanacConduitAPIMethod.php b/src/applications/almanac/conduit/AlmanacConduitAPIMethod.php deleted file mode 100644 index b7eec60cb4..0000000000 --- a/src/applications/almanac/conduit/AlmanacConduitAPIMethod.php +++ /dev/null @@ -1,73 +0,0 @@ - (int)$service->getID(), - 'phid' => $service->getPHID(), - 'name' => $service->getName(), - 'uri' => PhabricatorEnv::getProductionURI($service->getURI()), - 'serviceClass' => $service->getServiceClass(), - 'properties' => $this->getPropertiesDictionary($service), - ); - } - - protected function getBindingDictionary(AlmanacBinding $binding) { - return array( - 'id' => (int)$binding->getID(), - 'phid' => $binding->getPHID(), - 'properties' => $this->getPropertiesDictionary($binding), - 'interface' => $this->getInterfaceDictionary($binding->getInterface()), - ); - } - - protected function getPropertiesDictionary(AlmanacPropertyInterface $obj) { - $properties = $obj->getAlmanacProperties(); - return (object)mpull($properties, 'getFieldValue', 'getFieldName'); - } - - protected function getInterfaceDictionary(AlmanacInterface $interface) { - return array( - 'id' => (int)$interface->getID(), - 'phid' => $interface->getPHID(), - 'address' => $interface->getAddress(), - 'port' => (int)$interface->getPort(), - 'device' => $this->getDeviceDictionary($interface->getDevice()), - 'network' => $this->getNetworkDictionary($interface->getNetwork()), - ); - } - - protected function getDeviceDictionary(AlmanacDevice $device) { - return array( - 'id' => (int)$device->getID(), - 'phid' => $device->getPHID(), - 'name' => $device->getName(), - 'properties' => $this->getPropertiesDictionary($device), - ); - } - - protected function getNetworkDictionary(AlmanacNetwork $network) { - return array( - 'id' => (int)$network->getID(), - 'phid' => $network->getPHID(), - 'name' => $network->getName(), - ); - } - -} diff --git a/src/applications/almanac/conduit/AlmanacQueryDevicesConduitAPIMethod.php b/src/applications/almanac/conduit/AlmanacQueryDevicesConduitAPIMethod.php deleted file mode 100644 index b0a593a381..0000000000 --- a/src/applications/almanac/conduit/AlmanacQueryDevicesConduitAPIMethod.php +++ /dev/null @@ -1,63 +0,0 @@ - 'optional list', - 'phids' => 'optional list', - 'names' => 'optional list', - ) + self::getPagerParamTypes(); - } - - protected function defineReturnType() { - return 'list'; - } - - protected function execute(ConduitAPIRequest $request) { - $viewer = $request->getUser(); - - $query = id(new AlmanacDeviceQuery()) - ->setViewer($viewer); - - $ids = $request->getValue('ids'); - if ($ids !== null) { - $query->withIDs($ids); - } - - $phids = $request->getValue('phids'); - if ($phids !== null) { - $query->withPHIDs($phids); - } - - $names = $request->getValue('names'); - if ($names !== null) { - $query->withNames($names); - } - - $pager = $this->newPager($request); - - $devices = $query->executeWithCursorPager($pager); - - $data = array(); - foreach ($devices as $device) { - $data[] = $this->getDeviceDictionary($device); - } - - $results = array( - 'data' => $data, - ); - - return $this->addPagerResults($results, $pager); - } - -} diff --git a/src/applications/almanac/conduit/AlmanacQueryServicesConduitAPIMethod.php b/src/applications/almanac/conduit/AlmanacQueryServicesConduitAPIMethod.php deleted file mode 100644 index 81e59d072f..0000000000 --- a/src/applications/almanac/conduit/AlmanacQueryServicesConduitAPIMethod.php +++ /dev/null @@ -1,86 +0,0 @@ - 'optional list', - 'phids' => 'optional list', - 'names' => 'optional list', - 'devicePHIDs' => 'optional list', - 'serviceClasses' => 'optional list', - ) + self::getPagerParamTypes(); - } - - protected function defineReturnType() { - return 'list'; - } - - protected function execute(ConduitAPIRequest $request) { - $viewer = $request->getUser(); - - $query = id(new AlmanacServiceQuery()) - ->setViewer($viewer) - ->needBindings(true); - - $ids = $request->getValue('ids'); - if ($ids !== null) { - $query->withIDs($ids); - } - - $phids = $request->getValue('phids'); - if ($phids !== null) { - $query->withPHIDs($phids); - } - - $names = $request->getValue('names'); - if ($names !== null) { - $query->withNames($names); - } - - $classes = $request->getValue('serviceClasses'); - if ($classes !== null) { - $query->withServiceClasses($classes); - } - - $device_phids = $request->getValue('devicePHIDs'); - if ($device_phids !== null) { - $query->withDevicePHIDs($device_phids); - } - - $pager = $this->newPager($request); - - $services = $query->executeWithCursorPager($pager); - - $data = array(); - foreach ($services as $service) { - $phid = $service->getPHID(); - - $service_bindings = $service->getBindings(); - $service_bindings = array_values($service_bindings); - foreach ($service_bindings as $key => $service_binding) { - $service_bindings[$key] = $this->getBindingDictionary($service_binding); - } - - $data[] = $this->getServiceDictionary($service) + array( - 'bindings' => $service_bindings, - ); - } - - $results = array( - 'data' => $data, - ); - - return $this->addPagerResults($results, $pager); - } - -} diff --git a/src/applications/almanac/controller/AlmanacServiceEditController.php b/src/applications/almanac/controller/AlmanacServiceEditController.php index 9a0d8d5d17..2b6f5a9f5d 100644 --- a/src/applications/almanac/controller/AlmanacServiceEditController.php +++ b/src/applications/almanac/controller/AlmanacServiceEditController.php @@ -34,21 +34,19 @@ final class AlmanacServiceEditController $this->requireApplicationCapability( AlmanacCreateServicesCapability::CAPABILITY); - $service_class = $request->getStr('serviceClass'); - $service_types = AlmanacServiceType::getAllServiceTypes(); - if (empty($service_types[$service_class])) { - return $this->buildServiceTypeResponse($service_types, $cancel_uri); + $service_type = $request->getStr('serviceType'); + + try { + $service = AlmanacService::initializeNewService($service_type); + } catch (Exception $ex) { + return $this->buildServiceTypeResponse($cancel_uri); } - $service_type = $service_types[$service_class]; - if ($service_type->isClusterServiceType()) { + if ($service->isClusterService()) { $this->requireApplicationCapability( AlmanacManageClusterServicesCapability::CAPABILITY); } - $service = AlmanacService::initializeNewService(); - $service->setServiceClass($service_class); - $service->attachServiceType($service_type); $is_new = true; $title = pht('Create Service'); @@ -125,7 +123,7 @@ final class AlmanacServiceEditController $form = id(new AphrontFormView()) ->setUser($viewer) ->addHiddenInput('edit', true) - ->addHiddenInput('serviceClass', $service->getServiceClass()) + ->addHiddenInput('serviceType', $service->getServiceType()) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Name')) @@ -177,7 +175,9 @@ final class AlmanacServiceEditController )); } - private function buildServiceTypeResponse(array $service_types, $cancel_uri) { + private function buildServiceTypeResponse($cancel_uri) { + $service_types = AlmanacServiceType::getAllServiceTypes(); + $request = $this->getRequest(); $viewer = $this->getViewer(); @@ -197,7 +197,7 @@ final class AlmanacServiceEditController $type_control = id(new AphrontFormRadioButtonControl()) ->setLabel(pht('Service Type')) - ->setName('serviceClass') + ->setName('serviceType') ->setError($e_service); foreach ($service_types as $service_type) { @@ -211,7 +211,7 @@ final class AlmanacServiceEditController } $type_control->addButton( - get_class($service_type), + $service_type->getServiceTypeConstant(), $service_type->getServiceTypeName(), array( $service_type->getServiceTypeDescription(), diff --git a/src/applications/almanac/controller/AlmanacServiceViewController.php b/src/applications/almanac/controller/AlmanacServiceViewController.php index 230cb56731..68defec4b9 100644 --- a/src/applications/almanac/controller/AlmanacServiceViewController.php +++ b/src/applications/almanac/controller/AlmanacServiceViewController.php @@ -76,7 +76,7 @@ final class AlmanacServiceViewController $properties->addProperty( pht('Service Type'), - $service->getServiceType()->getServiceTypeShortName()); + $service->getServiceImplementation()->getServiceTypeShortName()); return $properties; } diff --git a/src/applications/almanac/query/AlmanacServiceQuery.php b/src/applications/almanac/query/AlmanacServiceQuery.php index e45cfec04b..3374413e5b 100644 --- a/src/applications/almanac/query/AlmanacServiceQuery.php +++ b/src/applications/almanac/query/AlmanacServiceQuery.php @@ -6,7 +6,7 @@ final class AlmanacServiceQuery private $ids; private $phids; private $names; - private $serviceClasses; + private $serviceTypes; private $devicePHIDs; private $namePrefix; private $nameSuffix; @@ -28,8 +28,8 @@ final class AlmanacServiceQuery return $this; } - public function withServiceClasses(array $classes) { - $this->serviceClasses = $classes; + public function withServiceTypes(array $types) { + $this->serviceTypes = $types; return $this; } @@ -109,11 +109,11 @@ final class AlmanacServiceQuery $hashes); } - if ($this->serviceClasses !== null) { + if ($this->serviceTypes !== null) { $where[] = qsprintf( $conn, - 'service.serviceClass IN (%Ls)', - $this->serviceClasses); + 'service.serviceType IN (%Ls)', + $this->serviceTypes); } if ($this->devicePHIDs !== null) { @@ -141,17 +141,19 @@ final class AlmanacServiceQuery } protected function willFilterPage(array $services) { - $service_types = AlmanacServiceType::getAllServiceTypes(); + $service_map = AlmanacServiceType::getAllServiceTypes(); foreach ($services as $key => $service) { - $service_class = $service->getServiceClass(); - $service_type = idx($service_types, $service_class); - if (!$service_type) { + $implementation = idx($service_map, $service->getServiceType()); + + if (!$implementation) { $this->didRejectResult($service); unset($services[$key]); continue; } - $service->attachServiceType($service_type); + + $implementation = clone $implementation; + $service->attachServiceImplementation($implementation); } return $services; diff --git a/src/applications/almanac/query/AlmanacServiceSearchEngine.php b/src/applications/almanac/query/AlmanacServiceSearchEngine.php index 1a15e17d46..1a9509a2c2 100644 --- a/src/applications/almanac/query/AlmanacServiceSearchEngine.php +++ b/src/applications/almanac/query/AlmanacServiceSearchEngine.php @@ -16,7 +16,7 @@ final class AlmanacServiceSearchEngine } public function newResultObject() { - return AlmanacService::initializeNewService(); + return new AlmanacService(); } protected function buildQueryFromParameters(array $map) { @@ -34,6 +34,10 @@ final class AlmanacServiceSearchEngine $query->withDevicePHIDs($map['devicePHIDs']); } + if ($map['serviceTypes']) { + $query->withServiceTypes($map['serviceTypes']); + } + return $query; } @@ -48,6 +52,11 @@ final class AlmanacServiceSearchEngine ->setLabel(pht('Exact Names')) ->setKey('names') ->setDescription(pht('Search for services with specific names.')), + id(new PhabricatorSearchDatasourceField()) + ->setLabel(pht('Service Types')) + ->setKey('serviceTypes') + ->setDescription(pht('Find services by type.')) + ->setDatasource(id(new AlmanacServiceTypeDatasource())), id(new PhabricatorPHIDsSearchField()) ->setLabel(pht('Devices')) ->setKey('devicePHIDs') @@ -98,8 +107,8 @@ final class AlmanacServiceSearchEngine ->setHref($service->getURI()) ->setObject($service) ->addIcon( - $service->getServiceType()->getServiceTypeIcon(), - $service->getServiceType()->getServiceTypeShortName()); + $service->getServiceImplementation()->getServiceTypeIcon(), + $service->getServiceImplementation()->getServiceTypeShortName()); $list->addItem($item); } diff --git a/src/applications/almanac/servicetype/AlmanacClusterDatabaseServiceType.php b/src/applications/almanac/servicetype/AlmanacClusterDatabaseServiceType.php index bbf7e9878c..ba06a78d52 100644 --- a/src/applications/almanac/servicetype/AlmanacClusterDatabaseServiceType.php +++ b/src/applications/almanac/servicetype/AlmanacClusterDatabaseServiceType.php @@ -3,6 +3,8 @@ final class AlmanacClusterDatabaseServiceType extends AlmanacClusterServiceType { + const SERVICETYPE = 'cluster.database'; + public function getServiceTypeShortName() { return pht('Cluster Database'); } diff --git a/src/applications/almanac/servicetype/AlmanacClusterRepositoryServiceType.php b/src/applications/almanac/servicetype/AlmanacClusterRepositoryServiceType.php index d33ee7167b..259092b5b1 100644 --- a/src/applications/almanac/servicetype/AlmanacClusterRepositoryServiceType.php +++ b/src/applications/almanac/servicetype/AlmanacClusterRepositoryServiceType.php @@ -3,6 +3,8 @@ final class AlmanacClusterRepositoryServiceType extends AlmanacClusterServiceType { + const SERVICETYPE = 'cluster.repository'; + public function getServiceTypeShortName() { return pht('Cluster Repository'); } diff --git a/src/applications/almanac/servicetype/AlmanacCustomServiceType.php b/src/applications/almanac/servicetype/AlmanacCustomServiceType.php index 3a4affbb8e..f4df57a868 100644 --- a/src/applications/almanac/servicetype/AlmanacCustomServiceType.php +++ b/src/applications/almanac/servicetype/AlmanacCustomServiceType.php @@ -2,6 +2,8 @@ final class AlmanacCustomServiceType extends AlmanacServiceType { + const SERVICETYPE = 'almanac.custom'; + public function getServiceTypeShortName() { return pht('Custom'); } diff --git a/src/applications/almanac/servicetype/AlmanacDrydockPoolServiceType.php b/src/applications/almanac/servicetype/AlmanacDrydockPoolServiceType.php index 24880565d0..4c7de3a361 100644 --- a/src/applications/almanac/servicetype/AlmanacDrydockPoolServiceType.php +++ b/src/applications/almanac/servicetype/AlmanacDrydockPoolServiceType.php @@ -2,6 +2,8 @@ final class AlmanacDrydockPoolServiceType extends AlmanacServiceType { + const SERVICETYPE = 'drydock.pool'; + public function getServiceTypeShortName() { return pht('Drydock Pool'); } diff --git a/src/applications/almanac/servicetype/AlmanacServiceType.php b/src/applications/almanac/servicetype/AlmanacServiceType.php index 043da7d52e..2eb56dc8c4 100644 --- a/src/applications/almanac/servicetype/AlmanacServiceType.php +++ b/src/applications/almanac/servicetype/AlmanacServiceType.php @@ -30,6 +30,11 @@ abstract class AlmanacServiceType extends Phobject { abstract public function getServiceTypeDescription(); + final public function getServiceTypeConstant() { + return $this->getPhobjectClassConstant('SERVICETYPE', 64); + } + + public function getServiceTypeIcon() { return 'fa-cog'; } @@ -38,7 +43,7 @@ abstract class AlmanacServiceType extends Phobject { * Return `true` if this service type is a Phabricator cluster service type. * * These special services change the behavior of Phabricator, and require - * elevated permission to create. + * elevated permission to create and edit. * * @return bool True if this is a Phabricator cluster service type. */ @@ -63,6 +68,7 @@ abstract class AlmanacServiceType extends Phobject { public static function getAllServiceTypes() { return id(new PhutilClassMapQuery()) ->setAncestorClass(__CLASS__) + ->setUniqueMethod('getServiceTypeConstant') ->setSortMethod('getServiceTypeName') ->execute(); } diff --git a/src/applications/almanac/storage/AlmanacProperty.php b/src/applications/almanac/storage/AlmanacProperty.php index e695da59ec..0d317f8c8e 100644 --- a/src/applications/almanac/storage/AlmanacProperty.php +++ b/src/applications/almanac/storage/AlmanacProperty.php @@ -39,6 +39,46 @@ final class AlmanacProperty return $this; } + public static function newPropertyUpdateTransactions( + AlmanacPropertyInterface $object, + array $properties, + $only_builtins = false) { + + $template = $object->getApplicationTransactionTemplate(); + $builtins = $object->getAlmanacPropertyFieldSpecifications(); + + $xactions = array(); + foreach ($properties as $name => $property) { + if ($only_builtins && empty($builtins[$name])) { + continue; + } + + $xactions[] = id(clone $template) + ->setTransactionType(AlmanacTransaction::TYPE_PROPERTY_UPDATE) + ->setMetadataValue('almanac.property', $name) + ->setNewValue($property); + } + + return $xactions; + } + + public static function newPropertyRemoveTransactions( + AlmanacPropertyInterface $object, + array $properties) { + + $template = $object->getApplicationTransactionTemplate(); + + $xactions = array(); + foreach ($properties as $property) { + $xactions[] = id(clone $template) + ->setTransactionType(AlmanacTransaction::TYPE_PROPERTY_REMOVE) + ->setMetadataValue('almanac.property', $property) + ->setNewValue(null); + } + + return $xactions; + } + public function save() { $hash = PhabricatorHash::digestForIndex($this->getFieldName()); $this->setFieldIndex($hash); diff --git a/src/applications/almanac/storage/AlmanacService.php b/src/applications/almanac/storage/AlmanacService.php index 92a5551188..b280de9ba8 100644 --- a/src/applications/almanac/storage/AlmanacService.php +++ b/src/applications/almanac/storage/AlmanacService.php @@ -17,17 +17,29 @@ final class AlmanacService protected $mailKey; protected $viewPolicy; protected $editPolicy; - protected $serviceClass; + protected $serviceType; private $almanacProperties = self::ATTACHABLE; private $bindings = self::ATTACHABLE; - private $serviceType = self::ATTACHABLE; + private $serviceImplementation = self::ATTACHABLE; + + public static function initializeNewService($type) { + $type_map = AlmanacServiceType::getAllServiceTypes(); + + $implementation = idx($type_map, $type); + if (!$implementation) { + throw new Exception( + pht( + 'No Almanac service type "%s" exists!', + $type)); + } - public static function initializeNewService() { return id(new AlmanacService()) ->setViewPolicy(PhabricatorPolicies::POLICY_USER) ->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN) - ->attachAlmanacProperties(array()); + ->attachAlmanacProperties(array()) + ->setServiceType($type) + ->attachServiceImplementation($implementation); } protected function getConfiguration() { @@ -37,7 +49,7 @@ final class AlmanacService 'name' => 'text128', 'nameIndex' => 'bytes12', 'mailKey' => 'bytes20', - 'serviceClass' => 'text64', + 'serviceType' => 'text64', ), self::CONFIG_KEY_SCHEMA => array( 'key_name' => array( @@ -47,8 +59,8 @@ final class AlmanacService 'key_nametext' => array( 'columns' => array('name'), ), - 'key_class' => array( - 'columns' => array('serviceClass'), + 'key_servicetype' => array( + 'columns' => array('serviceType'), ), ), ) + parent::getConfiguration(); @@ -78,22 +90,35 @@ final class AlmanacService return $this->assertAttached($this->bindings); } + public function getActiveBindings() { + $bindings = $this->getBindings(); + + // Filter out disabled bindings. + foreach ($bindings as $key => $binding) { + if ($binding->getIsDisabled()) { + unset($bindings[$key]); + } + } + + return $bindings; + } + public function attachBindings(array $bindings) { $this->bindings = $bindings; return $this; } - public function getServiceType() { - return $this->assertAttached($this->serviceType); + public function getServiceImplementation() { + return $this->assertAttached($this->serviceImplementation); } - public function attachServiceType(AlmanacServiceType $type) { - $this->serviceType = $type; + public function attachServiceImplementation(AlmanacServiceType $type) { + $this->serviceImplementation = $type; return $this; } public function isClusterService() { - return $this->getServiceType()->isClusterServiceType(); + return $this->getServiceImplementation()->isClusterServiceType(); } @@ -128,7 +153,7 @@ final class AlmanacService } public function getAlmanacPropertyFieldSpecifications() { - return $this->getServiceType()->getFieldSpecifications(); + return $this->getServiceImplementation()->getFieldSpecifications(); } public function newAlmanacPropertyEditEngine() { @@ -246,12 +271,17 @@ final class AlmanacService ->setKey('name') ->setType('string') ->setDescription(pht('The name of the service.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('serviceType') + ->setType('string') + ->setDescription(pht('The service type constant.')), ); } public function getFieldValuesForConduit() { return array( 'name' => $this->getName(), + 'serviceType' => $this->getServiceType(), ); } diff --git a/src/applications/almanac/typeahead/AlmanacServiceDatasource.php b/src/applications/almanac/typeahead/AlmanacServiceDatasource.php index 621b0408ae..4413465125 100644 --- a/src/applications/almanac/typeahead/AlmanacServiceDatasource.php +++ b/src/applications/almanac/typeahead/AlmanacServiceDatasource.php @@ -28,9 +28,9 @@ final class AlmanacServiceDatasource // selected, or show all services but mark the invalid ones disabled and // prevent their selection. - $service_classes = $this->getParameter('serviceClasses'); - if ($service_classes) { - $services->withServiceClasses($service_classes); + $service_types = $this->getParameter('serviceTypes'); + if ($service_types) { + $services->withServiceTypes($service_types); } $services = $this->executeQuery($services); diff --git a/src/applications/almanac/typeahead/AlmanacServiceTypeDatasource.php b/src/applications/almanac/typeahead/AlmanacServiceTypeDatasource.php new file mode 100644 index 0000000000..5314084244 --- /dev/null +++ b/src/applications/almanac/typeahead/AlmanacServiceTypeDatasource.php @@ -0,0 +1,43 @@ +buildResults(); + return $this->filterResultsAgainstTokens($results); + } + + protected function renderSpecialTokens(array $values) { + return $this->renderTokensFromResults($this->buildResults(), $values); + } + + private function buildResults() { + $results = array(); + + $types = AlmanacServiceType::getAllServiceTypes(); + + $results = array(); + foreach ($types as $key => $type) { + $results[$key] = id(new PhabricatorTypeaheadResult()) + ->setName($type->getServiceTypeName()) + ->setIcon($type->getServiceTypeIcon()) + ->setPHID($key); + } + + return $results; + } + +} diff --git a/src/applications/config/check/PhabricatorRepositoriesSetupCheck.php b/src/applications/config/check/PhabricatorRepositoriesSetupCheck.php index 89967f7eaa..64073ec1ed 100644 --- a/src/applications/config/check/PhabricatorRepositoriesSetupCheck.php +++ b/src/applications/config/check/PhabricatorRepositoriesSetupCheck.php @@ -10,9 +10,9 @@ final class PhabricatorRepositoriesSetupCheck extends PhabricatorSetupCheck { $cluster_services = id(new AlmanacServiceQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withServiceClasses( + ->withServiceTypes( array( - 'AlmanacClusterRepositoryServiceType', + AlmanacClusterRepositoryServiceType::SERVICETYPE, )) ->setLimit(1) ->execute(); diff --git a/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php b/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php index bfd01ff30c..a9113fee13 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php @@ -47,9 +47,9 @@ final class DiffusionRepositoryCreateController // allocations, we fail. $services = id(new AlmanacServiceQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withServiceClasses( + ->withServiceTypes( array( - 'AlmanacClusterRepositoryServiceType', + AlmanacClusterRepositoryServiceType::SERVICETYPE, )) ->needProperties(true) ->execute(); diff --git a/src/applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php index 3a742a72c2..443b0e8965 100644 --- a/src/applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php +++ b/src/applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php @@ -184,7 +184,7 @@ final class DrydockAlmanacServiceHostBlueprintImplementation 'type' => 'datasource', 'datasource.class' => 'AlmanacServiceDatasource', 'datasource.parameters' => array( - 'serviceClasses' => $this->getAlmanacServiceClasses(), + 'serviceTypes' => $this->getAlmanacServiceTypes(), ), 'required' => true, ), @@ -213,7 +213,7 @@ final class DrydockAlmanacServiceHostBlueprintImplementation $services = id(new AlmanacServiceQuery()) ->setViewer($viewer) ->withPHIDs($service_phids) - ->withServiceClasses($this->getAlmanacServiceClasses()) + ->withServiceTypes($this->getAlmanacServiceTypes()) ->needBindings(true) ->execute(); $services = mpull($services, null, 'getPHID'); @@ -283,9 +283,9 @@ final class DrydockAlmanacServiceHostBlueprintImplementation return $this->freeBindings; } - private function getAlmanacServiceClasses() { + private function getAlmanacServiceTypes() { return array( - 'AlmanacDrydockPoolServiceType', + AlmanacDrydockPoolServiceType::SERVICETYPE, ); } diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php index e6510e7ad9..9896a8ef29 100644 --- a/src/applications/repository/storage/PhabricatorRepository.php +++ b/src/applications/repository/storage/PhabricatorRepository.php @@ -2047,7 +2047,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO 'be loaded.')); } - $service_type = $service->getServiceType(); + $service_type = $service->getServiceImplementation(); if (!($service_type instanceof AlmanacClusterRepositoryServiceType)) { throw new Exception( pht(