diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 6eb2bc9873..9d1fb6fd7b 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -65,6 +65,7 @@ phutil_register_library_map(array( 'AlmanacPropertyEditController' => 'applications/almanac/controller/AlmanacPropertyEditController.php', 'AlmanacPropertyInterface' => 'applications/almanac/property/AlmanacPropertyInterface.php', 'AlmanacPropertyQuery' => 'applications/almanac/query/AlmanacPropertyQuery.php', + 'AlmanacQuery' => 'applications/almanac/query/AlmanacQuery.php', 'AlmanacService' => 'applications/almanac/storage/AlmanacService.php', 'AlmanacServiceController' => 'applications/almanac/controller/AlmanacServiceController.php', 'AlmanacServiceEditController' => 'applications/almanac/controller/AlmanacServiceEditController.php', @@ -2972,11 +2973,14 @@ phutil_register_library_map(array( 'AlmanacBinding' => array( 'AlmanacDAO', 'PhabricatorPolicyInterface', + 'PhabricatorCustomFieldInterface', + 'PhabricatorApplicationTransactionInterface', + 'AlmanacPropertyInterface', ), 'AlmanacBindingEditController' => 'AlmanacServiceController', 'AlmanacBindingEditor' => 'PhabricatorApplicationTransactionEditor', 'AlmanacBindingPHIDType' => 'PhabricatorPHIDType', - 'AlmanacBindingQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'AlmanacBindingQuery' => 'AlmanacQuery', 'AlmanacBindingTableView' => 'AphrontView', 'AlmanacBindingTransaction' => 'PhabricatorApplicationTransaction', 'AlmanacBindingTransactionQuery' => 'PhabricatorApplicationTransactionQuery', @@ -2996,13 +3000,16 @@ phutil_register_library_map(array( 'AlmanacDevice' => array( 'AlmanacDAO', 'PhabricatorPolicyInterface', + 'PhabricatorCustomFieldInterface', + 'PhabricatorApplicationTransactionInterface', + 'AlmanacPropertyInterface', ), 'AlmanacDeviceController' => 'AlmanacController', 'AlmanacDeviceEditController' => 'AlmanacDeviceController', 'AlmanacDeviceEditor' => 'PhabricatorApplicationTransactionEditor', 'AlmanacDeviceListController' => 'AlmanacDeviceController', 'AlmanacDevicePHIDType' => 'PhabricatorPHIDType', - 'AlmanacDeviceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'AlmanacDeviceQuery' => 'AlmanacQuery', 'AlmanacDeviceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'AlmanacDeviceTransaction' => 'PhabricatorApplicationTransaction', 'AlmanacDeviceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', @@ -3041,6 +3048,7 @@ phutil_register_library_map(array( 'AlmanacPropertyController' => 'AlmanacController', 'AlmanacPropertyEditController' => 'AlmanacDeviceController', 'AlmanacPropertyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'AlmanacQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'AlmanacService' => array( 'AlmanacDAO', 'PhabricatorPolicyInterface', @@ -3053,7 +3061,7 @@ phutil_register_library_map(array( 'AlmanacServiceEditor' => 'PhabricatorApplicationTransactionEditor', 'AlmanacServiceListController' => 'AlmanacServiceController', 'AlmanacServicePHIDType' => 'PhabricatorPHIDType', - 'AlmanacServiceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'AlmanacServiceQuery' => 'AlmanacQuery', 'AlmanacServiceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'AlmanacServiceTransaction' => 'PhabricatorApplicationTransaction', 'AlmanacServiceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', diff --git a/src/applications/almanac/controller/AlmanacBindingViewController.php b/src/applications/almanac/controller/AlmanacBindingViewController.php index b7ff42ce03..55286b60e3 100644 --- a/src/applications/almanac/controller/AlmanacBindingViewController.php +++ b/src/applications/almanac/controller/AlmanacBindingViewController.php @@ -57,6 +57,7 @@ final class AlmanacBindingViewController array( $crumbs, $box, + $this->buildAlmanacPropertiesTable($binding), $xaction_view, ), array( diff --git a/src/applications/almanac/controller/AlmanacController.php b/src/applications/almanac/controller/AlmanacController.php index bc7d2ee8f6..1c2d62ef59 100644 --- a/src/applications/almanac/controller/AlmanacController.php +++ b/src/applications/almanac/controller/AlmanacController.php @@ -3,14 +3,11 @@ abstract class AlmanacController extends PhabricatorController { + protected function buildAlmanacPropertiesTable( + AlmanacPropertyInterface $object) { - protected function buildAlmanacPropertiesTable($object) { $viewer = $this->getViewer(); - - $properties = id(new AlmanacPropertyQuery()) - ->setViewer($viewer) - ->withObjectPHIDs(array($object->getPHID())) - ->execute(); + $properties = $object->getAlmanacProperties(); $rows = array(); foreach ($properties as $property) { diff --git a/src/applications/almanac/controller/AlmanacDeviceViewController.php b/src/applications/almanac/controller/AlmanacDeviceViewController.php index 15c9102487..60edf5d24a 100644 --- a/src/applications/almanac/controller/AlmanacDeviceViewController.php +++ b/src/applications/almanac/controller/AlmanacDeviceViewController.php @@ -56,6 +56,7 @@ final class AlmanacDeviceViewController $crumbs, $box, $interfaces, + $this->buildAlmanacPropertiesTable($device), $xaction_view, ), array( diff --git a/src/applications/almanac/controller/AlmanacServiceViewController.php b/src/applications/almanac/controller/AlmanacServiceViewController.php index fb7675551f..6e07daf0bb 100644 --- a/src/applications/almanac/controller/AlmanacServiceViewController.php +++ b/src/applications/almanac/controller/AlmanacServiceViewController.php @@ -15,7 +15,6 @@ final class AlmanacServiceViewController $service = id(new AlmanacServiceQuery()) ->setViewer($viewer) ->withNames(array($name)) - ->needProperties(true) ->executeOne(); if (!$service) { return new Aphront404Response(); diff --git a/src/applications/almanac/query/AlmanacBindingQuery.php b/src/applications/almanac/query/AlmanacBindingQuery.php index 28bb25f598..dd4336db8c 100644 --- a/src/applications/almanac/query/AlmanacBindingQuery.php +++ b/src/applications/almanac/query/AlmanacBindingQuery.php @@ -1,7 +1,7 @@ formatWhereClause($where); } - public function getQueryApplicationClass() { - return 'PhabricatorAlmanacApplication'; - } - } diff --git a/src/applications/almanac/query/AlmanacDeviceQuery.php b/src/applications/almanac/query/AlmanacDeviceQuery.php index f5928d5819..b5e797849b 100644 --- a/src/applications/almanac/query/AlmanacDeviceQuery.php +++ b/src/applications/almanac/query/AlmanacDeviceQuery.php @@ -1,7 +1,7 @@ ids = $ids; + return $this; + } public function withObjectPHIDs(array $phids) { $this->phids = $phids; @@ -16,6 +23,15 @@ final class AlmanacPropertyQuery return $this; } + public function setDisablePolicyFilteringAndAttachment($disable) { + $this->disablePolicyFilteringAndAttachment = $disable; + return $this; + } + + protected function shouldDisablePolicyFiltering() { + return $this->disablePolicyFilteringAndAttachment; + } + protected function loadPage() { $table = new AlmanacProperty(); $conn_r = $table->establishConnection('r'); @@ -32,22 +48,24 @@ final class AlmanacPropertyQuery } protected function willFilterPage(array $properties) { - $object_phids = mpull($properties, 'getObjectPHID'); + if (!$this->disablePolicyFilteringAndAttachment) { + $object_phids = mpull($properties, 'getObjectPHID'); - $objects = id(new PhabricatorObjectQuery()) - ->setViewer($this->getViewer()) - ->setParentQuery($this) - ->withPHIDs($object_phids) - ->execute(); - $objects = mpull($objects, null, 'getPHID'); + $objects = id(new PhabricatorObjectQuery()) + ->setViewer($this->getViewer()) + ->setParentQuery($this) + ->withPHIDs($object_phids) + ->execute(); + $objects = mpull($objects, null, 'getPHID'); - foreach ($properties as $key => $property) { - $object = idx($objects, $property->getObjectPHID()); - if (!$object) { - unset($properties[$key]); - continue; + foreach ($properties as $key => $property) { + $object = idx($objects, $property->getObjectPHID()); + if (!$object) { + unset($properties[$key]); + continue; + } + $property->attachObject($object); } - $property->attachObject($object); } return $properties; @@ -56,6 +74,13 @@ final class AlmanacPropertyQuery protected function buildWhereClause($conn_r) { $where = array(); + if ($this->ids !== null) { + $where[] = qsprintf( + $conn_r, + 'id IN (%Ld)', + $this->ids); + } + if ($this->objectPHIDs !== null) { $where[] = qsprintf( $conn_r, diff --git a/src/applications/almanac/query/AlmanacQuery.php b/src/applications/almanac/query/AlmanacQuery.php new file mode 100644 index 0000000000..7c0ad75ef8 --- /dev/null +++ b/src/applications/almanac/query/AlmanacQuery.php @@ -0,0 +1,41 @@ +setViewer($this->getViewer()) + ->setParentQuery($this) + ->withObjectPHIDs(mpull($objects, null, 'getPHID')); + + // NOTE: We disable policy filtering and object attachment to avoid + // a cyclic dependency where objects need their properties and properties + // need their objects. We'll attach the objects below, and have already + // implicitly checked the necessary policies. + $property_query->setDisablePolicyFilteringAndAttachment(true); + + $properties = $property_query->execute(); + $properties = mgroup($properties, 'getObjectPHID'); + foreach ($objects as $object) { + $object_properties = idx($properties, $object->getPHID(), array()); + foreach ($object_properties as $property) { + $property->attachObject($object); + } + $object->attachAlmanacProperties($object_properties); + } + } + + return $objects; + } + + public function getQueryApplicationClass() { + return 'PhabricatorAlmanacApplication'; + } + +} diff --git a/src/applications/almanac/query/AlmanacServiceQuery.php b/src/applications/almanac/query/AlmanacServiceQuery.php index 61ee741e50..84e1250cbd 100644 --- a/src/applications/almanac/query/AlmanacServiceQuery.php +++ b/src/applications/almanac/query/AlmanacServiceQuery.php @@ -1,12 +1,11 @@ ids = $ids; @@ -23,11 +22,6 @@ final class AlmanacServiceQuery return $this; } - public function needProperties($need) { - $this->needProperties = $need; - return $this; - } - protected function loadPage() { $table = new AlmanacService(); $conn_r = $table->establishConnection('r'); @@ -77,27 +71,4 @@ final class AlmanacServiceQuery return $this->formatWhereClause($where); } - protected function didFilterPage(array $services) { - // NOTE: We load properties unconditionally because CustomField assumes - // it can always generate a list of fields on an object. It may make - // sense to re-examine that assumption eventually. - - $properties = id(new AlmanacPropertyQuery()) - ->setViewer($this->getViewer()) - ->setParentQuery($this) - ->withObjectPHIDs(mpull($services, null, 'getPHID')) - ->execute(); - $properties = mgroup($properties, 'getObjectPHID'); - foreach ($services as $service) { - $service_properties = idx($properties, $service->getPHID(), array()); - $service->attachAlmanacProperties($service_properties); - } - - return $services; - } - - public function getQueryApplicationClass() { - return 'PhabricatorAlmanacApplication'; - } - } diff --git a/src/applications/almanac/storage/AlmanacBinding.php b/src/applications/almanac/storage/AlmanacBinding.php index 74e7e57de7..8294817da9 100644 --- a/src/applications/almanac/storage/AlmanacBinding.php +++ b/src/applications/almanac/storage/AlmanacBinding.php @@ -2,7 +2,11 @@ final class AlmanacBinding extends AlmanacDAO - implements PhabricatorPolicyInterface { + implements + PhabricatorPolicyInterface, + PhabricatorCustomFieldInterface, + PhabricatorApplicationTransactionInterface, + AlmanacPropertyInterface { protected $servicePHID; protected $devicePHID; @@ -12,6 +16,8 @@ final class AlmanacBinding private $service = self::ATTACHABLE; private $device = self::ATTACHABLE; private $interface = self::ATTACHABLE; + private $customFields = self::ATTACHABLE; + private $almanacProperties = self::ATTACHABLE; public static function initializeNewBinding(AlmanacService $service) { return id(new AlmanacBinding()) @@ -82,6 +88,37 @@ final class AlmanacBinding } +/* -( AlmanacPropertyInterface )------------------------------------------- */ + + + public function attachAlmanacProperties(array $properties) { + assert_instances_of($properties, 'AlmanacProperty'); + $this->almanacProperties = mpull($properties, null, 'getFieldName'); + return $this; + } + + public function getAlmanacProperties() { + return $this->assertAttached($this->almanacProperties); + } + + public function hasAlmanacProperty($key) { + $this->assertAttached($this->almanacProperties); + return isset($this->almanacProperties[$key]); + } + + public function getAlmanacProperty($key) { + return $this->assertAttachedKey($this->almanacProperties, $key); + } + + public function getAlmanacPropertyValue($key, $default = null) { + if ($this->hasAlmanacProperty($key)) { + return $this->getAlmanacProperty($key)->getFieldValue(); + } else { + return $default; + } + } + + /* -( PhabricatorPolicyInterface )----------------------------------------- */ @@ -109,4 +146,41 @@ final class AlmanacBinding ); } + +/* -( PhabricatorCustomFieldInterface )------------------------------------ */ + + + public function getCustomFieldSpecificationForRole($role) { + return array(); + } + + public function getCustomFieldBaseClass() { + return 'AlmanacCustomField'; + } + + public function getCustomFields() { + return $this->assertAttached($this->customFields); + } + + public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { + $this->customFields = $fields; + return $this; + } + + +/* -( PhabricatorApplicationTransactionInterface )------------------------- */ + + + public function getApplicationTransactionEditor() { + return new AlmanacBindingEditor(); + } + + public function getApplicationTransactionObject() { + return $this; + } + + public function getApplicationTransactionTemplate() { + return new AlmanacBindingTransaction(); + } + } diff --git a/src/applications/almanac/storage/AlmanacDevice.php b/src/applications/almanac/storage/AlmanacDevice.php index 52d7c453e8..34ec9ff608 100644 --- a/src/applications/almanac/storage/AlmanacDevice.php +++ b/src/applications/almanac/storage/AlmanacDevice.php @@ -2,7 +2,11 @@ final class AlmanacDevice extends AlmanacDAO - implements PhabricatorPolicyInterface { + implements + PhabricatorPolicyInterface, + PhabricatorCustomFieldInterface, + PhabricatorApplicationTransactionInterface, + AlmanacPropertyInterface { protected $name; protected $nameIndex; @@ -10,6 +14,9 @@ final class AlmanacDevice protected $viewPolicy; protected $editPolicy; + private $customFields = self::ATTACHABLE; + private $almanacProperties = self::ATTACHABLE; + public static function initializeNewDevice() { return id(new AlmanacDevice()) ->setViewPolicy(PhabricatorPolicies::POLICY_USER) @@ -57,6 +64,37 @@ final class AlmanacDevice } +/* -( AlmanacPropertyInterface )------------------------------------------- */ + + + public function attachAlmanacProperties(array $properties) { + assert_instances_of($properties, 'AlmanacProperty'); + $this->almanacProperties = mpull($properties, null, 'getFieldName'); + return $this; + } + + public function getAlmanacProperties() { + return $this->assertAttached($this->almanacProperties); + } + + public function hasAlmanacProperty($key) { + $this->assertAttached($this->almanacProperties); + return isset($this->almanacProperties[$key]); + } + + public function getAlmanacProperty($key) { + return $this->assertAttachedKey($this->almanacProperties, $key); + } + + public function getAlmanacPropertyValue($key, $default = null) { + if ($this->hasAlmanacProperty($key)) { + return $this->getAlmanacProperty($key)->getFieldValue(); + } else { + return $default; + } + } + + /* -( PhabricatorPolicyInterface )----------------------------------------- */ @@ -84,4 +122,41 @@ final class AlmanacDevice return null; } + +/* -( PhabricatorCustomFieldInterface )------------------------------------ */ + + + public function getCustomFieldSpecificationForRole($role) { + return array(); + } + + public function getCustomFieldBaseClass() { + return 'AlmanacCustomField'; + } + + public function getCustomFields() { + return $this->assertAttached($this->customFields); + } + + public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { + $this->customFields = $fields; + return $this; + } + + +/* -( PhabricatorApplicationTransactionInterface )------------------------- */ + + + public function getApplicationTransactionEditor() { + return new AlmanacDeviceEditor(); + } + + public function getApplicationTransactionObject() { + return $this; + } + + public function getApplicationTransactionTemplate() { + return new AlmanacDeviceTransaction(); + } + }