mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-25 14:08:19 +01:00
Support export engine extensions and implement an extension for custom fields
Summary: Depends on D18953. Ref T13049. Allow applications and infrastructure to supplement exportable fields for objects. Then, implement an extension for custom fields. Only a couple field types (int, string) are supported for now. Test Plan: Added some custom fields to Users, populated them, exported users. Saw custom fields in the export. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13049 Differential Revision: https://secure.phabricator.com/D18954
This commit is contained in:
parent
8b8a3142b3
commit
a067f64ebb
8 changed files with 233 additions and 0 deletions
|
@ -2583,6 +2583,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCustomFieldEditEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php',
|
'PhabricatorCustomFieldEditEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php',
|
||||||
'PhabricatorCustomFieldEditField' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php',
|
'PhabricatorCustomFieldEditField' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php',
|
||||||
'PhabricatorCustomFieldEditType' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditType.php',
|
'PhabricatorCustomFieldEditType' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditType.php',
|
||||||
|
'PhabricatorCustomFieldExportEngineExtension' => 'infrastructure/export/PhabricatorCustomFieldExportEngineExtension.php',
|
||||||
'PhabricatorCustomFieldFulltextEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldFulltextEngineExtension.php',
|
'PhabricatorCustomFieldFulltextEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldFulltextEngineExtension.php',
|
||||||
'PhabricatorCustomFieldHeraldAction' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldAction.php',
|
'PhabricatorCustomFieldHeraldAction' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldAction.php',
|
||||||
'PhabricatorCustomFieldHeraldActionGroup' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldActionGroup.php',
|
'PhabricatorCustomFieldHeraldActionGroup' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldActionGroup.php',
|
||||||
|
@ -2847,6 +2848,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php',
|
'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php',
|
||||||
'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php',
|
'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php',
|
||||||
'PhabricatorExecFutureFileUploadSource' => 'applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php',
|
'PhabricatorExecFutureFileUploadSource' => 'applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php',
|
||||||
|
'PhabricatorExportEngineExtension' => 'infrastructure/export/PhabricatorExportEngineExtension.php',
|
||||||
'PhabricatorExportField' => 'infrastructure/export/PhabricatorExportField.php',
|
'PhabricatorExportField' => 'infrastructure/export/PhabricatorExportField.php',
|
||||||
'PhabricatorExportFormat' => 'infrastructure/export/PhabricatorExportFormat.php',
|
'PhabricatorExportFormat' => 'infrastructure/export/PhabricatorExportFormat.php',
|
||||||
'PhabricatorExtendedPolicyInterface' => 'applications/policy/interface/PhabricatorExtendedPolicyInterface.php',
|
'PhabricatorExtendedPolicyInterface' => 'applications/policy/interface/PhabricatorExtendedPolicyInterface.php',
|
||||||
|
@ -7991,6 +7993,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCustomFieldEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
'PhabricatorCustomFieldEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
||||||
'PhabricatorCustomFieldEditField' => 'PhabricatorEditField',
|
'PhabricatorCustomFieldEditField' => 'PhabricatorEditField',
|
||||||
'PhabricatorCustomFieldEditType' => 'PhabricatorEditType',
|
'PhabricatorCustomFieldEditType' => 'PhabricatorEditType',
|
||||||
|
'PhabricatorCustomFieldExportEngineExtension' => 'PhabricatorExportEngineExtension',
|
||||||
'PhabricatorCustomFieldFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
'PhabricatorCustomFieldFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
||||||
'PhabricatorCustomFieldHeraldAction' => 'HeraldAction',
|
'PhabricatorCustomFieldHeraldAction' => 'HeraldAction',
|
||||||
'PhabricatorCustomFieldHeraldActionGroup' => 'HeraldActionGroup',
|
'PhabricatorCustomFieldHeraldActionGroup' => 'HeraldActionGroup',
|
||||||
|
@ -8280,6 +8283,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorEventType' => 'PhutilEventType',
|
'PhabricatorEventType' => 'PhutilEventType',
|
||||||
'PhabricatorExampleEventListener' => 'PhabricatorEventListener',
|
'PhabricatorExampleEventListener' => 'PhabricatorEventListener',
|
||||||
'PhabricatorExecFutureFileUploadSource' => 'PhabricatorFileUploadSource',
|
'PhabricatorExecFutureFileUploadSource' => 'PhabricatorFileUploadSource',
|
||||||
|
'PhabricatorExportEngineExtension' => 'Phobject',
|
||||||
'PhabricatorExportField' => 'Phobject',
|
'PhabricatorExportField' => 'Phobject',
|
||||||
'PhabricatorExportFormat' => 'Phobject',
|
'PhabricatorExportFormat' => 'Phobject',
|
||||||
'PhabricatorExtendingPhabricatorConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorExtendingPhabricatorConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
|
|
|
@ -1483,6 +1483,26 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
$fields[$key] = $export_field;
|
$fields[$key] = $export_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$extensions = $this->newExportExtensions();
|
||||||
|
foreach ($extensions as $extension) {
|
||||||
|
$extension_fields = $extension->newExportFields();
|
||||||
|
foreach ($extension_fields as $extension_field) {
|
||||||
|
$key = $extension_field->getKey();
|
||||||
|
|
||||||
|
if (isset($fields[$key])) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Export engine extension ("%s") defines an export field with '.
|
||||||
|
'a key ("%s") that collides with another field. Each field '.
|
||||||
|
'must have a unique key.',
|
||||||
|
get_class($extension_field),
|
||||||
|
$key));
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields[$key] = $extension_field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1514,6 +1534,25 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
$maps[$ii] += $export_data[$ii];
|
$maps[$ii] += $export_data[$ii];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$extensions = $this->newExportExtensions();
|
||||||
|
foreach ($extensions as $extension) {
|
||||||
|
$extension_data = $extension->newExportData($objects);
|
||||||
|
$extension_data = array_values($extension_data);
|
||||||
|
if (count($export_data) !== count($objects)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Export engine extension ("%s") exported the wrong number of '.
|
||||||
|
'objects, expected %s but got %s.',
|
||||||
|
get_class($extension),
|
||||||
|
phutil_count($objects),
|
||||||
|
phutil_count($export_data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($ii = 0; $ii < $n; $ii++) {
|
||||||
|
$maps[$ii] += $extension_data[$ii];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $maps;
|
return $maps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1525,4 +1564,23 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
throw new PhutilMethodNotImplementedException();
|
throw new PhutilMethodNotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function newExportExtensions() {
|
||||||
|
$object = $this->newResultObject();
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
$extensions = PhabricatorExportEngineExtension::getAllExtensions();
|
||||||
|
|
||||||
|
$supported = array();
|
||||||
|
foreach ($extensions as $extension) {
|
||||||
|
$extension = clone $extension;
|
||||||
|
$extension->setViewer($viewer);
|
||||||
|
|
||||||
|
if ($extension->supportsObject($object)) {
|
||||||
|
$supported[] = $extension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $supported;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ abstract class PhabricatorCustomField extends Phobject {
|
||||||
const ROLE_HERALD = 'herald';
|
const ROLE_HERALD = 'herald';
|
||||||
const ROLE_EDITENGINE = 'EditEngine';
|
const ROLE_EDITENGINE = 'EditEngine';
|
||||||
const ROLE_HERALDACTION = 'herald.action';
|
const ROLE_HERALDACTION = 'herald.action';
|
||||||
|
const ROLE_EXPORT = 'export';
|
||||||
|
|
||||||
|
|
||||||
/* -( Building Applications with Custom Fields )--------------------------- */
|
/* -( Building Applications with Custom Fields )--------------------------- */
|
||||||
|
@ -299,6 +300,8 @@ abstract class PhabricatorCustomField extends Phobject {
|
||||||
case self::ROLE_EDITENGINE:
|
case self::ROLE_EDITENGINE:
|
||||||
return $this->shouldAppearInEditView() ||
|
return $this->shouldAppearInEditView() ||
|
||||||
$this->shouldAppearInEditEngine();
|
$this->shouldAppearInEditEngine();
|
||||||
|
case self::ROLE_EXPORT:
|
||||||
|
return $this->shouldAppearInDataExport();
|
||||||
case self::ROLE_DEFAULT:
|
case self::ROLE_DEFAULT:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
@ -1362,6 +1365,46 @@ abstract class PhabricatorCustomField extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Data Export )-------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function shouldAppearInDataExport() {
|
||||||
|
if ($this->proxy) {
|
||||||
|
return $this->proxy->shouldAppearInDataExport();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->newExportFieldType();
|
||||||
|
return true;
|
||||||
|
} catch (PhabricatorCustomFieldImplementationIncompleteException $ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportField() {
|
||||||
|
if ($this->proxy) {
|
||||||
|
return $this->proxy->newExportField();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newExportFieldType()
|
||||||
|
->setLabel($this->getFieldName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportData() {
|
||||||
|
if ($this->proxy) {
|
||||||
|
return $this->proxy->newExportData();
|
||||||
|
}
|
||||||
|
throw new PhabricatorCustomFieldImplementationIncompleteException($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newExportFieldType() {
|
||||||
|
if ($this->proxy) {
|
||||||
|
return $this->proxy->newExportFieldType();
|
||||||
|
}
|
||||||
|
throw new PhabricatorCustomFieldImplementationIncompleteException($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( Conduit )------------------------------------------------------------ */
|
/* -( Conduit )------------------------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -496,5 +496,8 @@ abstract class PhabricatorStandardCustomField
|
||||||
return $this->getFieldValue();
|
return $this->getFieldValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newExportData() {
|
||||||
|
return $this->getFieldValue();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,4 +124,8 @@ final class PhabricatorStandardCustomFieldInt
|
||||||
return new ConduitIntParameterType();
|
return new ConduitIntParameterType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function newExportFieldType() {
|
||||||
|
return new PhabricatorIntExportField();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,4 +76,8 @@ final class PhabricatorStandardCustomFieldText
|
||||||
return new ConduitStringParameterType();
|
return new ConduitStringParameterType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function newExportFieldType() {
|
||||||
|
return new PhabricatorStringExportField();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCustomFieldExportEngineExtension
|
||||||
|
extends PhabricatorExportEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'custom-field';
|
||||||
|
|
||||||
|
private $object;
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
$this->object = $object;
|
||||||
|
return ($object instanceof PhabricatorCustomFieldInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportFields() {
|
||||||
|
$prototype = $this->object;
|
||||||
|
|
||||||
|
$fields = $this->newCustomFields($prototype);
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$field_key = $field->getModernFieldKey();
|
||||||
|
|
||||||
|
$results[] = $field->newExportField()
|
||||||
|
->setKey($field_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newExportData(array $objects) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$field_map = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$object_phid = $object->getPHID();
|
||||||
|
|
||||||
|
$fields = PhabricatorCustomField::getObjectFields(
|
||||||
|
$object,
|
||||||
|
PhabricatorCustomField::ROLE_EXPORT);
|
||||||
|
|
||||||
|
$fields
|
||||||
|
->setViewer($viewer)
|
||||||
|
->readFieldsFromObject($object);
|
||||||
|
|
||||||
|
$field_map[$object_phid] = $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
$all_fields = array();
|
||||||
|
foreach ($field_map as $field_list) {
|
||||||
|
foreach ($field_list->getFields() as $field) {
|
||||||
|
$all_fields[] = $field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
id(new PhabricatorCustomFieldStorageQuery())
|
||||||
|
->addFields($all_fields)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$object_phid = $object->getPHID();
|
||||||
|
$object_fields = $field_map[$object_phid];
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($object_fields->getFields() as $field) {
|
||||||
|
$key = $field->getModernFieldKey();
|
||||||
|
$map[$key] = $field->newExportData();
|
||||||
|
}
|
||||||
|
|
||||||
|
$results[] = $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newCustomFields($object) {
|
||||||
|
$fields = PhabricatorCustomField::getObjectFields(
|
||||||
|
$object,
|
||||||
|
PhabricatorCustomField::ROLE_EXPORT);
|
||||||
|
$fields->setViewer($this->getViewer());
|
||||||
|
|
||||||
|
return $fields->getFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorExportEngineExtension extends Phobject {
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
|
||||||
|
final public function getExtensionKey() {
|
||||||
|
return $this->getPhobjectClassConstant('EXTENSIONKEY');
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function setViewer($viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getViewer() {
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function supportsObject($object);
|
||||||
|
abstract public function newExportFields();
|
||||||
|
abstract public function newExportData(array $objects);
|
||||||
|
|
||||||
|
final public static function getAllExtensions() {
|
||||||
|
return id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->setUniqueMethod('getExtensionKey')
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue